分享
  1. 首页
  2. 文章

golang用TCP协议实现简单的聊天室

ustb80 · · 2352 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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

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

客户端:
连接服务器;
向服务器发送消息;
接收服务器的广播消息;

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

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

服务器:

server.go

package main
import (
 "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 main
import (
 "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中输入字符并回车,可以看到别的终端都会收到消息;


有疑问加站长微信联系(非本文作者)

本文来自:51CTO博客

感谢作者:ustb80

查看原文:golang用TCP协议实现简单的聊天室

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
2352 次点击
2 回复 | 直到 2018年07月09日 16:11:21
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏