1 架构图
2 user.go
package mainimport "net"type User struct {Name stringAddr string // 当前客户端的ip地址C chan stringconn net.Conn}func NewUser(conn net.Conn) *User {userAddr := conn.RemoteAddr().String()user := &User{Name: userAddr,Addr: userAddr,C: make(chan string),conn: conn,}// 启动go程go user.ListenMessage()return user}// 监听当前User的channel,一旦有消息就直接发给客户端func (this *User) ListenMessage() {for {msg := <-this.Cthis.conn.Write([]byte(msg + "\n"))}}
3 server.go
package mainimport ("fmt""net""sync")type Server struct {Ip stringPort int// 在线用户列表OnlineMap map[string]*UsermapLock sync.RWMutex// 消息广播的channelMessage chan string}// 创建func NewServer(ip string, port int) *Server {server := &Server{Ip: ip,Port: port,OnlineMap: make(map[string]*User),Message: make(chan string),}return server}// 广播消息的方法func (this *Server) BroadCast(user *User, msg string) {sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msgthis.Message <- sendMsg}// 监听message消息的GO程, 一旦有消息就发给全部在线的Userfunc (this *Server) ListenMessage() {for {msg := <-this.Message// 将msg发送给全部在线的Userthis.mapLock.Lock()for _, cli := range this.OnlineMap {cli.C <- msg}this.mapLock.Unlock()}}// 处理业务func (this *Server) Handler(conn net.Conn) {user := NewUser(conn)// 用户上线, 将用户加入到OnlineMap中this.mapLock.Lock()this.OnlineMap[user.Name] = userthis.mapLock.Unlock()// 广播当前用户的上线消息this.BroadCast(user, "已上线")// 当前handler阻塞select {}}// 启动服务器的接口函数func (this *Server) Start() {// 创建一个监听套接字listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", this.Ip, this.Port))if err != nil {fmt.Println("net.Listen err:", err)return}defer listener.Close()// 启动监听消息的go程go this.ListenMessage()// 创建新套接字, 处理客户端的请求for {conn, err := listener.Accept()if err != nil {fmt.Println("listener accept err:", err)continue}go this.Handler(conn)}}
4 编绎运行
编绎服务端
go build -o server main.go server.go user.go
运行服务端
./server
模拟客户端向服务端发起连接
nc 127.0.0.1 8888

