千家信息网

go语言如何实现即时通讯聊天室

发表于:2024-12-13 作者:千家信息网编辑
千家信息网最后更新 2024年12月13日,本文小编为大家详细介绍"go语言如何实现即时通讯聊天室",内容详细,步骤清晰,细节处理妥当,希望这篇"go语言如何实现即时通讯聊天室"文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知
千家信息网最后更新 2024年12月13日go语言如何实现即时通讯聊天室

本文小编为大家详细介绍"go语言如何实现即时通讯聊天室",内容详细,步骤清晰,细节处理妥当,希望这篇"go语言如何实现即时通讯聊天室"文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

实现的功能:公聊,私聊,修改用户名

只用到了四个类:

  • main.go:用来启动服务器

  • server.go:服务器相关代码

  • client.go:客户端相关代码,用户可以直接操作的可视化界面

  • user.go:用户类,用来封装用户的业务逻辑

架构图

完整代码

server.go

package mainimport (        "fmt"        "io"        "net"        "sync"        "time")type Server struct {        Ip   string        Port int        //在线用户列表        OnlineMap map[string]*User        mapLock   sync.RWMutex        //消息广播的Channel        Message 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 (s *Server) Handler(conn net.Conn) {        //业务逻辑        //fmt.Println("链接建立成功")        user := NewUser(conn, s)        user.Online()        //监听用户是否活跃        isLive := make(chan bool)        go func() {                buf := make([]byte, 4096)                for {                        n, error := conn.Read(buf)                        if n == 0 {                                user.Offline()                                return                        }                        if error != nil && error != io.EOF {                                fmt.Println("read error")                        }                        msg := string(buf[:n-1])                        user.DoMessage(msg)                        //表示用户活跃                        isLive <- true                }        }()        for {                select {                case <-isLive:                        //当前用户活跃,不做任何时,激活select,重置定时器                case <-time.After(time.Second * 300):                        //超时,将user强制关闭                        user.SendMsg("你被踢了")                        close(user.C)                        conn.Close()                        return                }        }}func (s *Server) ListenMessager() {        for {                msg := <-s.Message                s.mapLock.Lock()                for _, user := range s.OnlineMap {                        user.C <- msg                }                s.mapLock.Unlock()        }}func (s *Server) BroadCast(user *User, msg string) {        sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msg        s.Message <- sendMsg}func (s *Server) Start() {        listener, error := net.Listen("tcp", fmt.Sprintf("%s:%d", s.Ip, s.Port))        if error != nil {                fmt.Println("listener error...")                return        }        defer listener.Close()        go s.ListenMessager()        for {                conn, error := listener.Accept()                if error != nil {                        fmt.Println("accept error...")                        continue                }                go s.Handler(conn)        }}

client.go

package mainimport (        "flag"        "fmt"        "io"        "net"        "os")type Client struct {        ServerIp   string        ServerPort int        Name       string        conn       net.Conn        flag       int}func NewClient(serverIp string, serverPort int) *Client {        client := &Client{                ServerIp:   serverIp,                ServerPort: serverPort,                flag:       9999,        }        conn, error := net.Dial("tcp", fmt.Sprintf("%s:%d", serverIp, serverPort))        if error != nil {                fmt.Println("net dial error...")                return nil        }        client.conn = conn        return client}func (c *Client) menu() bool {        var flag int        fmt.Println("1.公聊模式")        fmt.Println("2.私聊模式")        fmt.Println("3.修改用户名")        fmt.Println("0.退出")        fmt.Scanln(&flag)        if flag >= 0 && flag <= 3 {                c.flag = flag                return true        } else {                fmt.Println(">>>>请输入合法数字<<<<")                return false        }}//修改用户名func (c *Client) UpdateName() bool {        fmt.Println(">>>>请输入用户名")        fmt.Scanln(&c.Name)        sendMsg := "rename|" + c.Name + "\n"        _, error := c.conn.Write([]byte(sendMsg))        if error != nil {                fmt.Println("conn.write error...")                return false        }        return true}//公聊func (c *Client) PublicChat() {        var chatMsg string        fmt.Println(">>>>请输入聊天内容,输入exit退出")        fmt.Scanln(&chatMsg)        for chatMsg != "exit" {                if len(chatMsg) != 0 {                        msg := chatMsg + "\n"                        _, error := c.conn.Write([]byte(msg))                        if error != nil {                                fmt.Println("conn.Write error....")                                break                        }                }                chatMsg = ""                fmt.Println(">>>>请输入聊天内容,输入exit退出")                fmt.Scanln(&chatMsg)        }}//私聊func (c *Client) PrivateChat() {        var remoteUser string        var chatMsg string        c.SelectUsers()        fmt.Println(">>>>请输入聊天对象的用户名,输入exit退出")        fmt.Scanln(&remoteUser)        for remoteUser != "exit" {                fmt.Println(">>>>请输入聊天内容,输入exit退出")                fmt.Scanln(&chatMsg)                for chatMsg != "exit" {                        if len(chatMsg) != 0 {                                msg := "to|" + remoteUser + "|" + chatMsg + "\n\n"                                _, error := c.conn.Write([]byte(msg))                                if error != nil {                                        fmt.Println("conn.Write error....")                                        break                                }                        }                        chatMsg = ""                        fmt.Println(">>>>请输入聊天内容,输入exit退出")                        fmt.Scanln(&chatMsg)                }                c.SelectUsers()                remoteUser = ""                fmt.Println(">>>>请输入聊天对象的用户名,输入exit退出")                fmt.Scanln(&remoteUser)        }}//查询在线用户func (c *Client) SelectUsers() {        sendMsg := "who\n"        _, error := c.conn.Write([]byte(sendMsg))        if error != nil {                fmt.Println("conn.Write error....")                return        }}//处理server返回的消息func (c *Client) DealResponse() {        io.Copy(os.Stdout, c.conn)}func (c *Client) Run() {        for c.flag != 0 {                for c.menu() != true {                }                switch c.flag {                case 1:                        //公聊                        c.PublicChat()                case 2:                        //私聊                        c.PrivateChat()                case 3:                        //修改用户名                        c.UpdateName()                }        }}var serverIp stringvar serverPort intfunc init() {        flag.StringVar(&serverIp, "ip", "127.0.0.1", "设置服务器IP地址(默认为127.0.0.1)")        flag.IntVar(&serverPort, "port", 8888, "设置服务器端口(默认为8888)")}func main() {        flag.Parse()        client := NewClient(serverIp, serverPort)        if client == nil {                fmt.Println(">>>>链接服务器失败")                return        }        go client.DealResponse()        fmt.Println(">>>>链接服务器成功")        client.Run()}

user.go

package mainimport (        "net"        "strings")type User struct {        Name   string        Addr   string        C      chan string        conn   net.Conn        server *Server}func NewUser(conn net.Conn, server *Server) *User {        userAddr := conn.RemoteAddr().String()        user := &User{                Name:   userAddr,                Addr:   userAddr,                C:      make(chan string),                conn:   conn,                server: server,        }        go user.ListenMessage()        return user}//用户上线func (u *User) Online() {        u.server.mapLock.Lock()        u.server.OnlineMap[u.Name] = u        u.server.mapLock.Unlock()        u.server.BroadCast(u, "上线")}//用户下线func (u *User) Offline() {        u.server.mapLock.Lock()        delete(u.server.OnlineMap, u.Name)        u.server.mapLock.Unlock()        u.server.BroadCast(u, "下线")}//给当前user的客户端发送消息func (u *User) SendMsg(msg string) {        u.conn.Write([]byte(msg))}//处理消息func (u *User) DoMessage(msg string) {        if msg == "who" {                //查询当前在线用户                u.server.mapLock.Lock()                for _, user := range u.server.OnlineMap {                        onlineMsg := "[" + user.Addr + "]" + user.Name + ":在线...\n"                        u.SendMsg(onlineMsg)                }                u.server.mapLock.Unlock()        } else if len(msg) > 7 && msg[:7] == "rename|" {                //修改用户名 rename|xxx                newName := strings.Split(msg, "|")[1]                //判断名字是否已经存在                _, ok := u.server.OnlineMap[newName]                if ok {                        u.SendMsg("用户名已存在\n")                } else {                        u.server.mapLock.Lock()                        delete(u.server.OnlineMap, u.Name)                        u.server.OnlineMap[newName] = u                        u.server.mapLock.Unlock()                        u.Name = newName                        u.SendMsg("用户名成功修改为:" + newName + "\n")                }        } else if len(msg) > 4 && msg[:3] == "to|" {                //私聊  to|zhangsan|你好                //获取对方用户名                remoteName := strings.Split(msg, "|")[1]                if remoteName == "" {                        u.SendMsg("用户名格式不对\n")                        return                }                //获取对方user                remoteUser, ok := u.server.OnlineMap[remoteName]                if !ok {                        u.SendMsg("用户不存在\n")                        return                }                //获取消息                msg := strings.Split(msg, "|")[2]                if msg == "" {                        u.SendMsg("无消息内容,重新发送\n")                }                //发送消息                remoteUser.SendMsg(u.Name + "对您说:" + msg)        } else {                u.server.BroadCast(u, msg)        }}func (u *User) ListenMessage() {        for {                msg := <-u.C                u.conn.Write([]byte(msg + "\n"))        }}

main.go

package mainfunc main() {        server := NewServer("127.0.0.1", 8888)        server.Start()}

读到这里,这篇"go语言如何实现即时通讯聊天室"文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注行业资讯频道。

0