博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
golang用TCP协议实现简单的聊天室
阅读量:7007 次
发布时间:2019-06-27

本文共 3728 字,大约阅读时间需要 12 分钟。

通常聊天室的架构分为服务器端和客户端:

服务器端:

接受来自于客户端的连接请求并建立连接;
所有客户端的连接会放进连接池中,用于广播消息;

客户端:

连接服务器;
向服务器发送消息;
接收服务器的广播消息;

注意事项:

某一个客户端断开连接后需要从连接池中摘除,并不再接收广播消息;
某一个客户端断开连接后不能影响服务器端或别的客户端的连接;

详细的代码如下,文档看注释就好了,不再细说:

服务器:

server.go

package mainimport (    "net"    "log"    "fmt")func main() {    port := "9090"    Start(port)}// 启动服务器func Start(port string) {    host := ":" + port    // 获取tcp地址    tcpAddr, err := net.ResolveTCPAddr("tcp4", host)    if err != nil {        log.Printf("resolve tcp addr failed: %v\n", err)        return    }    // 监听    listener, err := net.ListenTCP("tcp", tcpAddr)    if err != nil {        log.Printf("listen tcp port failed: %v\n", err)        return    }    // 建立连接池,用于广播消息    conns := make(map[string]net.Conn)    // 消息通道    messageChan := make(chan string, 10)    // 广播消息    go BroadMessages(&conns, messageChan)    // 启动    for {        fmt.Printf("listening port %s ...\n", port)        conn, err := listener.AcceptTCP()        if err != nil {            log.Printf("Accept failed:%v\n", err)            continue        }        // 把每个客户端连接扔进连接池        conns[conn.RemoteAddr().String()] = conn        fmt.Println(conns)        // 处理消息        go Handler(conn, &conns, messageChan)    }}// 向所有连接上的乡亲们发广播func BroadMessages(conns *map[string]net.Conn, messages chan string) {    for {        // 不断从通道里读取消息        msg := <-messages        fmt.Println(msg)        // 向所有的乡亲们发消息        for key, conn := range *conns {            fmt.Println("connection is connected from ", key)            _, err := conn.Write([]byte(msg))            if err != nil {                log.Printf("broad message to %s failed: %v\n", key, err)                delete(*conns, key)            }        }    }}// 处理客户端发到服务端的消息,将其扔到通道中func Handler(conn net.Conn, conns *map[string]net.Conn, messages chan string) {    fmt.Println("connect from client ", conn.RemoteAddr().String())    buf := make([]byte, 1024)    for {        length, err := conn.Read(buf)        if err != nil {            log.Printf("read client message failed:%v\n", err)            delete(*conns, conn.RemoteAddr().String())            conn.Close()            break        }        // 把收到的消息写到通道中        recvStr := string(buf[0:length])        messages <- recvStr    }}

客户端:

client.go

package mainimport (    "net"    "log"    "fmt"    "os")func main() {    Start(os.Args[1])}func Start(tcpAddrStr string) {    tcpAddr, err := net.ResolveTCPAddr("tcp4", tcpAddrStr)    if err != nil {        log.Printf("Resolve tcp addr failed: %v\n", err)        return    }    // 向服务器拨号    conn, err := net.DialTCP("tcp", nil, tcpAddr)    if err != nil {        log.Printf("Dial to server failed: %v\n", err)        return    }    // 向服务器发消息    go SendMsg(conn)    // 接收来自服务器端的广播消息    buf := make([]byte, 1024)    for {        length, err := conn.Read(buf)        if err != nil {            log.Printf("recv server msg failed: %v\n", err)            conn.Close()            os.Exit(0)            break        }        fmt.Println(string(buf[0:length]))    }}// 向服务器端发消息func SendMsg(conn net.Conn) {    username := conn.LocalAddr().String()    for {        var input string        // 接收输入消息,放到input变量中        fmt.Scanln(&input)        if input == "/q" || input == "/quit" {            fmt.Println("Byebye ...")            conn.Close()            os.Exit(0)        }        // 只处理有内容的消息        if len(input) > 0 {            msg := username + " say:" + input            _, err := conn.Write([]byte(msg))            if err != nil {                conn.Close()                break            }        }    }}

测试方法:

编译server.go和client.go;

打开终端,启动server,默认会监听9090端口;
再打开多个终端,启动client,client启动命令:client 服务器IP:9090;
在client中输入字符并回车,可以看到别的终端都会收到消息;

转载于:https://blog.51cto.com/ustb80/2105678

你可能感兴趣的文章
U盘启动盘制作工具分享: 大白菜
查看>>
EditPlus 正则表达式
查看>>
HDUOJ----专题训练C
查看>>
Cannot lock storage /tmp/hadoop-root/dfs/name. The directory is already locked.
查看>>
BFS和DFS的java实现
查看>>
LCT
查看>>
数组名和指针区别
查看>>
uva10970 Big Chocolate
查看>>
CSS3属性-webkit-font-smoothing字体抗锯齿渲染
查看>>
对MVVM架构的一些理解
查看>>
一个通过物理地址查询网卡所属厂商的Python库——mac.py
查看>>
rundeck yum 安装完成后跳转http://localhost:4440/menu/home问题解决 ...
查看>>
02-Windows Server 2012 R2 会话远程桌面-快速部署(RemoteApp)
查看>>
asp.net 1.1 web.config 讲解
查看>>
Java☞DES加解密算法简介及实现
查看>>
Drupal7核心安装篇-Ubuntu 14.04 LTS
查看>>
ORA-06550 ,has been detected in fnd_global.initialize[fnd_init_sql].
查看>>
android Scroller
查看>>
微信小程序把玩(二)window配置
查看>>
微信公众平台开发(106) 网页获取用户地理位置
查看>>