1.server端代码如下:
package main
import (
"fmt"
"net"
)
//定义一个映射类型,用于存放每次请求的主机和Conn连接的对应关系
var TcpHostMap map[string]net.Conn
func HandleTcpReq(conn net.Conn) {
for {
ctx := make([]byte, 512)
if _, err := conn.Read(ctx); err != nil {
fmt.Println(conn.RemoteAddr().String() + "连接断开" + err.Error())
break
}
//广播发送消息到所有客户端,除去当前的发送请求的客户端
for k, v := range TcpHostMap {
if conn.RemoteAddr().String() == v.RemoteAddr().String() {
continue
}
if _, err := v.Write(ctx); err != nil {
fmt.Println(k+"已经退出", err)
delete(TcpHostMap, k)
}
}
}
defer conn.Close()
}
func main() {
Addr := "localhost:9191"
Network := "tcp"
TcpHostMap = make(map[string]net.Conn)
listener, err := net.Listen(Network, Addr)
if err != nil {
fmt.Println(err)
return
}
for {
Conn, err := listener.Accept()
if err == nil {
fmt.Println("已建立连接" + Conn.RemoteAddr().String())
} else {
Conn.Close()
}
TcpHostMap[Conn.RemoteAddr().String()] = Conn
fmt.Println(TcpHostMap)
go HandleTcpReq(Conn)
}
defer listener.Close()
}
2.客户端代码如下:
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main() {
var nickname, msg string
Scanner := bufio.NewScanner(os.Stdin)
Addr := "localhost:9191"
Network := "tcp"
Conn, err := net.Dial(Network, Addr)
fmt.Print("请输入您在群聊中的昵称: ")
fmt.Scanln(&nickname)
if nickname != "" {
fmt.Println("欢迎" + "<" + nickname + ">" + "加入群聊")
}
//通过go例程单独用于读取服务端响应数据
go func() {
for {
ctx := make([]byte, 512)
if _, err := Conn.Read(ctx); err != nil {
fmt.Println("服务端连接异常: ", err)
break
}
fmt.Println(string(ctx))
}
defer Conn.Close()
}()
for {
Scanner.Scan() //此处建议用bufio中的scan,因fmt.Scan会将空格作为捕获分割
msg = Scanner.Text()
if msg == "exit" || msg == "quit" {
fmt.Println("已断开连接")
break
}
if msg != "" || msg != "\n" {
_, err = Conn.Write([]byte("<" + nickname + ">:" + msg))
if err != nil {
fmt.Println("服务端连接异常: ", err)
break
}
}
}
defer Conn.Close()
}
3.最终实现的效果如下:
