经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Go语言 » 查看文章
GO使用socket和channel实现简单控制台聊天室
来源:jb51  时间:2021/12/20 17:34:33  对本文有异议

使用socket和channel,实现简单控制台聊天室

这里使用socket和channel,演示在GO中如何编写一个简单网络程序

功能分析

聊天室主要功能:用户可以加入/离开聊天室;每个用户发送的消息,广播给所有人
聊天室分为客户端和服务端,客户端负责发送消息和打印服务器消息,服务器负责接收客户端消息,并广播给所有人
客户端可以使用telnet程序
服务端是需要实现的。需要实现的功能,

  1. 如何保存多个客户端的连接,管理连接的接入与断开
  2. 如何接收和广播客户端消息

实现思路

通过功能分析,拆分为聊天室结构体和客户端结构体
聊天室结构体负责管理当前接入的客户端和广播消息
客户端结构体负责管理socket连接和需要接收与发送的数据
客户端连接/断开时通知聊天室;客户端发送的消息实际是转发给聊天室,然后聊天室再广播出去

完整代码

  1. package main
  2.  
  3. import (
  4. "bufio"
  5. "fmt"
  6. "log"
  7. "net"
  8. )
  9.  
  10. type Client struct {
  11. id string
  12. conn *net.Conn
  13. message chan string
  14. }
  15.  
  16. type Hub struct {
  17. clients map[*Client]bool
  18. entering chan *Client
  19. leaving chan *Client
  20. messages chan string
  21. }
  22.  
  23. func main() {
  24. hub := &Hub{
  25. clients: make(map[*Client]bool),
  26. entering: make(chan *Client),
  27. leaving: make(chan *Client),
  28. messages: make(chan string),
  29. }
  30.  
  31. listener, err := net.Listen("tcp", ":8000")
  32. if err != nil {
  33. log.Fatal(err)
  34. }
  35. go hub.broadcaster()
  36. for {
  37. conn, err := listener.Accept()
  38. if err != nil {
  39. log.Println(err)
  40. continue
  41. }
  42. go hub.handleConn(conn)
  43. }
  44. }
  45.  
  46. func (hub *Hub) broadcaster() {
  47. for {
  48. select {
  49. case msg := <-hub.messages:
  50. for cli := range hub.clients {
  51. cli.message <- msg
  52. }
  53. case cli := <-hub.entering:
  54. hub.clients[cli] = true
  55. case cli := <-hub.leaving:
  56. delete(hub.clients, cli)
  57. }
  58. }
  59. }
  60.  
  61. func (hub *Hub) handleConn(conn net.Conn) {
  62. defer conn.Close()
  63. ch := make(chan string)
  64. who := conn.RemoteAddr().String()
  65. client := &Client{who, &conn, ch}
  66.  
  67. go hub.writeLoop(client)
  68. ch <- "welcome " + client.id
  69.  
  70. hub.messages <- client.id + " join chat"
  71. hub.entering <- client
  72. hub.readLoop(client)
  73. hub.messages <- client.id + " has left"
  74. hub.leaving <- client
  75. }
  76.  
  77. func (hub *Hub) writeLoop(client *Client) {
  78. for msg := range client.message {
  79. fmt.Fprintf(*client.conn, "%s\n", msg)
  80. }
  81. }
  82.  
  83. func (hub *Hub) readLoop(client *Client) {
  84. input := bufio.NewScanner(*client.conn)
  85. for input.Scan() {
  86. hub.messages <- client.id + ": " + input.Text()
  87. }
  88. }

分析

实现的关键是封装了客户端通信channel,无论是远程发送过来的消息还是聊天室广播的消息,都通过这个channel传递,且这个channel是绑定客户端的
参考链接中,直接使用channel来定义客户端type client chan<- string,其实更能表达这一点
为了容易理解,这里将channel封装为客户端的一个通信管道,客户端还可以有别的属性,例如:id、连接和超时时间等

参考: Go 网络编程示例

到此这篇关于GO实现简单控制台聊天室的文章就介绍到这了,更多相关go控制台聊天室内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号