Ubuntu下Go语言TCP广播服务器实现

最近在学习Go语言网络编程,突然想到很久以前的用C语言写过的TCP广播聊天程序,然后就用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
", 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
", msg.User, msg.Content)
	}
}

func writeMsg(conn net.Conn) {
	for true {
		// 从标准输入生成读对象
		reader := bufio.NewReader(os.Stdin)
		// 读到换行
		content, _ := reader.ReadBytes(
)
		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

经验分享 程序员 微信小程序 职场和发展