Go语言实现的并发聊天室(二)

搭建程序主体(二)

1. 定义变量

// 定义一个结构体,保存客户端信息
type Client struct {
	C    chan string
	Name string
	Addr string
}
// 定义message管道,负责传递用户消息
var message = make(chan string)
// 定义一个map,保存客户端IP和客户端
var onlineMap map[string]Client

2. 主协程实现


func main() {
	fmt.Println("服务器启动了...")
	// 启动监听器,监听8888端口
	lntr, err := net.Listen("tcp", "127.0.0.1:8888")
	if (err != nil) {
		fmt.Println("net.Listen err: ", err)
		return
	}
	// 关闭监听器
	defer lntr.Close()

	// 启动Manager协程,负责监听Message通道数据变化
	go Manager()

	// 循环监听客户端连接
	for {
		conn, err := lntr.Accept()
		if err != nil {
			fmt.Println("lntr.Accept err: ", err)
			return
		}
		// 如果有客户端连接,就启动HandleConnect协程处理该连接
		go HandleConnect(conn)
	}

}

 3. 定义manager函数,负责初始化map集合,以及从message管道中读取客户端的消息。

func Manager() {
	//初始化map
	onlineMap = make(map[string]Client)

	//广播消息
	for {
		msg := <-message
		for _, client := range onlineMap {
			client.C <- msg
		}
	}
}

4. 实现HandleConnect函数,负责监听Message通道的数据。

func HandleConnect(conn net.Conn) {
	// 关闭客户端连接
	defer conn.Close()
	// 保存用户到map中
	addr := conn.RemoteAddr().String() //获取IP地址
	client := Client{make(chan string), addr, addr}
	onlineMap[addr] = client
	// 启动WriterMsgToClient协程,监听Client通道中数据变化
	go WriterMsgToClient(conn, client)
	// 登录消息
	userInfo := "[" + addr + "]" + addr + ": login\n"
	// 向所有用户广播消息
	message <- userInfo
	// 启动协程,负责读取客户端发送过来消息
	go func() {
		buf := make([]byte, 4096)
		for {
			n, err := conn.Read(buf)
			if n == 0 {
				fmt.Println("客户端连接已断开!")
				return
			}
			if err != nil {
				fmt.Println("conn.Read err: ", err)
				return
			}
			//读取到用户发送的消息
			msg := string(buf[:n-1])
			userInfo = "[" + client.Addr + "]" + client.Name + ":" + msg + "\n"
			//群发消息
			message <- userInfo
		}
	}()

	// 让HandleConnect协程不停止
	for {
		;
	}

}

5. 定义WriteMsgToClient函数,负责不断从Client通道中读取消息,然后把读取到的消息发送给客户端。

func WriterMsgToClient(conn net.Conn, client Client) {
	for {
		msg := <-client.C
		conn.Write([]byte(msg))
	}
}

猜你喜欢

转载自blog.csdn.net/zhongliwen1981/article/details/88804523