最近在学习Go语言网络编程,突然想到很久以前的用C语言写过的TCP广播聊天程序,然后就用Go尝试写了一遍,在此做个记录。
目录
1.广播结构
2.实现效果
3.源码
4.Go语言学习参考网站
1.广播结构
2.实现效果
服务器:
客户端1:
客户端2:
客户端3:
3.源码
server.go
package main
import (
"encoding/json"
"fmt"
"net"
"strings"
)
// client info
type Client struct {
Chan chan []byte
Addr string
}
// 广播信息
type Msg struct {
Content string
User string
}
// 客户端信息存储,IP和端口字符串为key
var onlineClients = make(map[string]Client)
// 广播消息的通道
var broadcastCh = make(chan Msg)
// 遍历通知客户端
func broadcastMessageManager() {
for {
//广播通道取数据
msg := <-broadcastCh
//遍历客户端发送数据
for _, client := range onlineClients {
msgBytes, _ := json.Marshal(msg)
client.Chan <- msgBytes
}
}
}
// 接收客户端消息,并将消息放入广播消息通道
func readClient(conn net.Conn) {
for true {
data := make([]byte, 1024)
n, _ := conn.Read(data)
content := strings.TrimSpace(string(data[:n]))
if len(content) <= 0 {
continue
}
broadcastCh <- Msg{Content: content, User: conn.RemoteAddr().String()}
fmt.Printf("%s say: %s\n", conn.RemoteAddr().String(), content)
}
}
// 通知客户端消息
func notifyMsgToClient(conn net.Conn, client Client) {
for {
msgBytes := <-client.Chan
_, _ = conn.Write(msgBytes)
}
}
func handleConnect(conn net.Conn) {
addr := conn.RemoteAddr().String()
fmt.Println("connect cilent: ", conn.RemoteAddr().String())
client := Client{make(chan []byte), addr}
onlineClients[addr] = client
content := client.Addr + " coming!"
broadcastCh <- Msg{Content: content, User: "system info"}
go readClient(conn)
go notifyMsgToClient(conn, client)
}
func main() {
fmt.Println("server starting ...")
listener, err := net.Listen("tcp", "127.0.0.1:8181")
if err != nil {
fmt.Println("net.Listen err: ", err)
return
}
//遍历通知客户端
go broadcastMessageManager()
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("listener.Accept err: ", err)
continue
}
//goroutine处理用户连接
go handleConnect(conn)
}
}
client.go
package main
import (
"bufio"
"encoding/json"
"fmt"
"net"
"os"
)
// 广播信息
type Msg struct {
Content string
User string
}
func readMsg(conn net.Conn) {
for {
res := make([]byte, 1024)
n, err := conn.Read(res)
if err != nil {
fmt.Println(err)
return
}
result := res[:n]
var msg Msg
json.Unmarshal(result, &msg)
fmt.Printf("%s: %s\n", msg.User, msg.Content)
}
}
func writeMsg(conn net.Conn) {
for true {
// 从标准输入生成读对象
reader := bufio.NewReader(os.Stdin)
// 读到换行
content, _ := reader.ReadBytes('\n')
if len(content) <= 0 {
continue
}
// 发送数据
conn.Write(content)
}
}
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:8181")
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
// 起goroutine接收服务器广播的消息
go readMsg(conn)
// 命令行接收输入并发送给服务器
writeMsg(conn)
}
4.Go语言学习参考网站
Go言入门教程:
http://c.biancheng.net/golang/
Go编程参考:
http://www.yuan316.com/post/Go%E8%AF%AD%E8%A8%80/
Go语言标准库:
https://pkg.go.dev/std
Go虎贲
https://www.zhihu.com/column/c_1438631789279076353