Go语言聊天室demo
话不多说直接上代码
Tcp服务端
package main
import (
"container/list"
"encoding/json"
"fmt"
uuid "github.com/satori/go.uuid"
"net"
"strings"
)
type GlobalConnInfo struct {
ClientConnMap map[string]net.Conn
ClientList list.List
}
type RespModel struct {
Code int
Msg string
Data any
}
func main() {
//这里维护了客户客户端的连接信息
globalConnInfo := GlobalConnInfo{ClientConnMap: make(map[string]net.Conn), ClientList: list.List{}}
//监听端口
listener, _ := net.Listen("tcp", ":9876")
fmt.Println("TCP服务器启动监听")
for {
//Listen返回成功后,这个服务会进入一个循环,调用net.Listener 的 Accept 方法接收新客户端连接
//在没有新连接的时候,这个服务会阻塞在 Accept 调用上,直到有客户端连接上来,Accept 方法将返回一个 net.Conn 实例,用于和新连上的客户端进行通信。
conn, _ := listener.Accept()
fmt.Println("【新的连接上来了, 启动新的协程处理】", conn)
//启动go协程, 处理conn的逻辑
go doSyncHandler(conn, globalConnInfo)
}
}
func doSyncHandler(conn net.Conn, globalConnInfo GlobalConnInfo) {
//重命名函数
name := serverFirstRename(conn)
//将name作为key维护连接
globalConnInfo.ClientConnMap[name] = conn
globalConnInfo.ClientList.PushBack(name)
//核心交互逻辑
for {
//定义读取数据读缓存数组
var readBytes []byte = make([]byte, 1024)
size, _ := conn.Read(readBytes)
//客户端给服务器发了数据服务端才返回
if size >= 0 {
action := strings.TrimSpace(string(readBytes))[:size]
fmt.Println("【server】[client ---> server] : ", action)
if action == "1" {
resultBytes, _ := json.Marshal(RespModel{Code: 200, Msg: "当前系统在线用户", Data: globalConnInfo})
conn.Write(resultBytes)
} else if action == "2" {
resultBytes, _ := json.Marshal(RespModel{Code: 200, Msg: "新用户昵称", Data: uuid.NewV1().String()[:32]})
conn.Write(resultBytes)
} else if action == "3" {
resultBytes, _ := json.Marshal(RespModel{Code: 200, Msg: "退出成功", Data: nil})
conn.Write(resultBytes)
} else {
resultBytes, _ := json.Marshal(RespModel{Code: 200, Msg: "暂未开发的操作, 请重新选择操作", Data: nil})
conn.Write(resultBytes)
}
}
}
}
func serverFirstRename(conn net.Conn) string {
//服务端随机命名
var name string = uuid.NewV1().String()[:32]
//返回服务端命名结果
firstWriteBytes := []byte(name)
conn.Write(firstWriteBytes)
fmt.Println("【server】[server ---> client] 服务端命名结果: ", string(firstWriteBytes))
return name
}
Tcp客户端
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
type RespModel struct {
Code int
Msg string
Data any
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
//Dial 函数向服务端发起 TCP 连接,这个函数会一直阻塞,直到连接成功或失败后,才会返回。
conn, _ := net.Dial("tcp", "localhost:9876")
fmt.Println("【客户端监听服务】")
//客户端命名
clientFirstRename(conn)
for {
//控制台读取
fmt.Println("您可以选择操作: 1.聊天, 2.系统重命名, 3.退出聊天室", actionMap)
scanner.Scan()
//定义写入缓存数组
writeBytes := []byte(strings.TrimSpace(scanner.Text()))
conn.Write(writeBytes)
fmt.Println("【client】[client ---> server] : ", string(writeBytes))
//定义读取数据读缓存数组
var readBytes []byte = make([]byte, 1024)
conn.Read(readBytes)
fmt.Println("【client】[server ---> client] : ", string(readBytes))
}
}
func clientFirstRename(conn net.Conn) {
//定义读取数据读缓存数组
var readBytes []byte = make([]byte, 1024)
conn.Read(readBytes)
fmt.Println("【client】[server ---> client] 来自服务端的名称:", string(readBytes))
}