• Go语言 之TCP聊天室


    服务端流程图如下:

    package main
    
    import (
        "fmt"
        "net"
    )
    
    // 客户端结构体
    type Client struct {
        //用户通信
        C chan string
        //客户端名称
        name string
        //客户端地址
        addr string
    }
    
    //map存储在线用户
    var is_online map[string]Client
    
    //消息通讯
    var messages = make(chan string)
    
    //广播全局消息到客户端
    func Message() {
        is_online = make(map[string]Client)
    
        // 循环读取 message 通道中的数据
        for {
            // 通道 message 中有数据读到 msg 中。 没有,则阻塞
            msg := <-messages
    
            // 一旦执行到这里,说明message中有数据了,解除阻塞。 遍历 map
            for _, client := range is_online {
                client.C <- msg // 把从Message通道中读到的数据,写到 client 的 C 通道中。
            }
        }
    }
    
    //生产消息函数
    func MakeMsg(client Client, msg string) (buf string) {
        buf = "[" + client.addr + "]" + client.name + ": " + msg
        return
    }
    
    //发送消息给在线客户端
    func WriteMsgToClient(conn net.Conn, client Client) {
        for msg := range client.C {
            conn.Write([]byte(msg))
        }
    }
    
    func Handler(conn net.Conn) {
    
        //把当前客户端添加到在线map中
        addr := conn.RemoteAddr().String()
        client := Client{make(chan string), addr, addr}
        //将当前客户端加入在线字典列表中
        is_online[addr] = client
    
        //创建一个协程,专门给当前客户端发消息
        go WriteMsgToClient(conn, client)
    
        //将用户上线的消息放到全局消息中
        messages <- MakeMsg(client, "login")
    
        // 创建一个新协程,循环读取用户发送的消息,广播给在线用户
        go func() {
            for {
                buf := make([]byte, 2048)
                //读取客户端数据
                n, _ := conn.Read(buf)
                if n == 0 {
                    fmt.Printf("用户%s退出登录
    ", client.name)
                    //将当前用户从在线字典中删除
                    delete(is_online, addr)
                    //通知其他客户端该用户退出登录
                    messages <- MakeMsg(client, "logout")
                    return
                }
                msg := string(buf[:n])
                //将客户端发的消息加入到全局消息通道中
                messages <- MakeMsg(client, msg)
            }
        }()
        //让协程不停止运行
        for {
    
        }
    }
    
    func main() {
        //奖励tcp监听
        listen, err := net.Listen("tcp", ":8000")
        if err != nil {
            fmt.Println(err.Error())
            return
        }
        defer listen.Close()
    
        //创建协程处理消息
        go Message()
    
        for {
            //阻塞等待客户端连接
            conn, err := listen.Accept()
            if err != nil {
                fmt.Println(err.Error())
            }
            //创建协程处理客户端事件
            go Handler(conn)
            defer conn.Close()
        }
    }

    效果图如下:

  • 相关阅读:
    敏捷软件开发实践-Code Review Process(转)
    随笔1
    随笔
    随笔
    低级错误
    随笔
    随笔2
    随笔
    这以前写的代码
    蛋疼的vs
  • 原文地址:https://www.cnblogs.com/yang-2018/p/11164279.html
Copyright © 2020-2023  润新知