1 架构图

image.png

2 user.go

  1. package main
  2. import "net"
  3. type User struct {
  4. Name string
  5. Addr string // 当前客户端的ip地址
  6. C chan string
  7. conn net.Conn
  8. }
  9. func NewUser(conn net.Conn) *User {
  10. userAddr := conn.RemoteAddr().String()
  11. user := &User{
  12. Name: userAddr,
  13. Addr: userAddr,
  14. C: make(chan string),
  15. conn: conn,
  16. }
  17. // 启动go程
  18. go user.ListenMessage()
  19. return user
  20. }
  21. // 监听当前User的channel,一旦有消息就直接发给客户端
  22. func (this *User) ListenMessage() {
  23. for {
  24. msg := <-this.C
  25. this.conn.Write([]byte(msg + "\n"))
  26. }
  27. }

3 server.go

  1. package main
  2. import (
  3. "fmt"
  4. "net"
  5. "sync"
  6. )
  7. type Server struct {
  8. Ip string
  9. Port int
  10. // 在线用户列表
  11. OnlineMap map[string]*User
  12. mapLock sync.RWMutex
  13. // 消息广播的channel
  14. Message chan string
  15. }
  16. // 创建
  17. func NewServer(ip string, port int) *Server {
  18. server := &Server{
  19. Ip: ip,
  20. Port: port,
  21. OnlineMap: make(map[string]*User),
  22. Message: make(chan string),
  23. }
  24. return server
  25. }
  26. // 广播消息的方法
  27. func (this *Server) BroadCast(user *User, msg string) {
  28. sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msg
  29. this.Message <- sendMsg
  30. }
  31. // 监听message消息的GO程, 一旦有消息就发给全部在线的User
  32. func (this *Server) ListenMessage() {
  33. for {
  34. msg := <-this.Message
  35. // 将msg发送给全部在线的User
  36. this.mapLock.Lock()
  37. for _, cli := range this.OnlineMap {
  38. cli.C <- msg
  39. }
  40. this.mapLock.Unlock()
  41. }
  42. }
  43. // 处理业务
  44. func (this *Server) Handler(conn net.Conn) {
  45. user := NewUser(conn)
  46. // 用户上线, 将用户加入到OnlineMap中
  47. this.mapLock.Lock()
  48. this.OnlineMap[user.Name] = user
  49. this.mapLock.Unlock()
  50. // 广播当前用户的上线消息
  51. this.BroadCast(user, "已上线")
  52. // 当前handler阻塞
  53. select {}
  54. }
  55. // 启动服务器的接口函数
  56. func (this *Server) Start() {
  57. // 创建一个监听套接字
  58. listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", this.Ip, this.Port))
  59. if err != nil {
  60. fmt.Println("net.Listen err:", err)
  61. return
  62. }
  63. defer listener.Close()
  64. // 启动监听消息的go程
  65. go this.ListenMessage()
  66. // 创建新套接字, 处理客户端的请求
  67. for {
  68. conn, err := listener.Accept()
  69. if err != nil {
  70. fmt.Println("listener accept err:", err)
  71. continue
  72. }
  73. go this.Handler(conn)
  74. }
  75. }

4 编绎运行

编绎服务端

go build -o server main.go server.go user.go

运行服务端

./server

模拟客户端向服务端发起连接

nc 127.0.0.1 8888

image.png