【Golang】✔️实战✔️ 聊天室 ☢️建议手收藏☢️

举报
我是小白呀iamarookie 发表于 2021/09/10 01:01:20 2021/09/10
【摘要】 【Golang】✔️实战✔️ 聊天室 ☢️建议手收藏☢️ 概述服务端实现客户端实现日志 概述 今天我们会结合之前几节课的知识来综合实战一下, 实现一个聊天室. 服务端实现 运行的时...

【Golang】✔️实战✔️ 聊天室 ☢️建议手收藏☢️

概述

今天我们会结合之前几节课的知识来综合实战一下, 实现一个聊天室.

在这里插入图片描述

服务端实现

运行的时候我们可以开启一个服务端和 N 个客户端, 来实现聊天室.

在这里插入图片描述
代码:

package main

import (
	"fmt"
	"log"
	"net"
	"os"
	"strings"
	"time"
)

// ================常量================
const (

	// 日志路径
	log_path = "chat_room/"
)


// ===============全局变量==============

// 文件日志
var logFile *os.File

// 日志类
var logger *log.Logger

// 客户端连接, key: ip端口, value: 连接对象
var onlineConns = make(map[string]net.Conn)

// 消息队列, 缓冲区
var message_quene = make(chan string, 1024)

// 消息, 处理程序退出
var quitchan = make(chan bool)

// 消息协程
func comsume_msg() {
	for {
		select {
		// 取出消息
		case msg := <- message_quene:
			process_msg(msg)
		// 处理退出
		case <- quitchan:
			break
		}
	}
}

// 消息解析协程
func process_msg(message string) {

	// 字符串切割
	contents := strings.Split(message, "#")
	if len(contents) > 1 {

		// 取出地址
		address := contents[0]

		// 取出消息
		message := contents[1]

		// 删除首尾
		address = strings.Trim(address, " ")

		// 在线连接
		conn, ok := onlineConns[address]

		if ok {
			_, err := conn.Write([]byte(message))
			fmt.Println("发送消息:", message, "目的地:", address)
			if err != nil {
				fmt.Println("在线连接发送失败")
			}
		}
	} else {


		// 查看list
		contents = strings.Split(message, "&")
		if contents[1] == "list" {

			var str = ""

			// 向每个客户端发送信息
			for i := range onlineConns {

				//
				str += "||||" + i
			}

			// 在线连接
			conn, ok := onlineConns[contents[0]]

			if ok {
				_, err := conn.Write([]byte(str))
				if err != nil {
					fmt.Println("在线发送失败:", err)
				}
			}
			fmt.Println("发送消息:", str, "目的地:", conn.RemoteAddr())
			logger.Println("发送消息:", str, "目的地:", conn.RemoteAddr())
		}
	}
}


// 接收消息
func receive_info(conn net.Conn) {

	// 缓冲
	buffer := make([]byte, 1024)

	// 循环读取
	for {

		// 读取数据
		nums, err := conn.Read(buffer)
		if err != nil {
			break
		}

		if nums != 0 {

			// 获取地址
			address := conn.RemoteAddr()

			// 获取消息
			message := string(buffer[:nums])

			// 调试输出
			fmt.Println("收到消息:", message, "来自:", address)
			logger.Println("收到消息:", message, "来自:", address)

			// 处理客户端退出
			if message == "exit" {

				// 调试输出
				fmt.Println("客户端:", conn.RemoteAddr(), "正在退出...")
				logger.Println("客户端:", conn.RemoteAddr(), "正在退出...")

				// 退出
				client_exit(conn)
			} else{
				// 消息队列存储消息
				message_quene <- message
			}
		}
	}
}

// 处理退出
func client_exit(conn net.Conn) {

	// 获取地址
	address := fmt.Sprint(conn.RemoteAddr())

	// 客户端退出时, 从map中移除地址
	delete(onlineConns, address)

	// 关闭连接
	conn.Close()

	// 输出当前列表
	fmt.Println("客户端列表:\n--------------------")
	logger.Println("客户端列表:\n--------------------")


	for i := range onlineConns {
		fmt.Println(i)
	}
}

// 错误处理
func error_check(err error) {
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(1)
	}
}

func main() {

	fmt.Println("服务端正在启动...")

	// 打开日志文件
	name := fmt.Sprintf("%d_%02d_%02d_%02d_%02d_%02d_server.log",
		time.Now().Year(),
		time.Now().Month(),
		time.Now().Day(),
		time.Now().Hour(),
	    time.Now().Minute(),
		time.Now().Second(),
	)

	log_file, err := os.OpenFile((log_path + name), os.O_RDWR | os.O_CREATE, 0)
	if err != nil {
		fmt.Println("日志文件打开失败:", err.Error())
		os.Exit(-1)
	}

	// 关闭
	defer log_file.Close()

	// 创建一个日志对象
	logger = log.New(log_file, "\r\n", log.Ldate | log.Ltime | log.Llongfile)
	logger.Println("写入日志, 服务器正在启动...")

	// 创建TCP服务端
	listen_socket, err := net.Listen("tcp", "127.0.0.1:8888")
	error_check(err)

	// 关闭
	defer listen_socket.Close()

	fmt.Println("服务端启动完毕, 等待连接...")

	// 协程
	go comsume_msg()

	// 启动连接
	for {

		// 连接新客户端
		conn, err := listen_socket.Accept()
		error_check(err)

		fmt.Println("服务端连接到客服端, 客户端地址:", conn.RemoteAddr())
		logger.Println("服务端连接到客服端, 客户端地址:", conn.RemoteAddr())


		// 获取地址
		address := fmt.Sprint(conn.RemoteAddr())

		// 添加到全局变量
		onlineConns[address] = conn

		// 遍历每一个连接
		fmt.Println("客户端列表:\n--------------------")
		logger.Println("客户端列表:\n---------------------------------------------------")
		for i := range onlineConns {
			fmt.Println(i)
			logger.Println(i)
		}

		// 发送消息
		go receive_info(conn)
	}

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251

客户端实现

package main

import (
	"bufio"
	"fmt"
	"net"
	"os"
)

// 发送消息
func send_msg(conn net.Conn) {

	// 循环发送
	for {

		// 读取键盘输入
		reader := bufio.NewReader(os.Stdin)

		// 读取一行
		data, _, _ := reader.ReadLine()

		// 发送输入的字符串
		_, err := conn.Write(data)
		fmt.Println("发送消息:", string(data))
		if err != nil {
			conn.Close()
			fmt.Println("Error:", err, "客户端关闭")
			os.Exit(0)
		}

		// 收到exit, 关闭客户端
		if string(data) == "exit" {
			fmt.Println("客户端关闭")
			os.Exit(0)
		}
	}
}

func main() {

	fmt.Println("客服端正在建立连接...")

	// 建立网络连接
	conn, err := net.Dial("tcp", "127.0.0.1:8888")
	if err != nil {
		fmt.Println("网络连接错误")
		os.Exit(1)
	}
	fmt.Println("客户端成功连接到服务端, 服务端地址:", conn.RemoteAddr())

	// 发送消息
	go send_msg(conn)

	// 接收消息
	buffer := make([]byte, 1024)

	// 循环接收
	for {
		// 读取消息
		nums, err := conn.Read(buffer)
		if err != nil {
			fmt.Println("读取消息出错, 退出客户端")
			os.Exit(0)
		}
		fmt.Println("收到消息:", string(buffer[:nums]))
	}

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

输出结果:
server:

服务端正在启动...
服务端启动完毕, 等待连接...
服务端连接到客服端, 客户端地址: 127.0.0.1:63776
客户端列表:
--------------------
127.0.0.1:63776
服务端连接到客服端, 客户端地址: 127.0.0.1:63777
客户端列表:
--------------------
127.0.0.1:63776
127.0.0.1:63777
收到消息: 127.0.0.1:63776&list 来自: 127.0.0.1:63776
发送消息: ||||127.0.0.1:63776||||127.0.0.1:63777 目的地: 127.0.0.1:63776
收到消息: 127.0.0.1:63777#hi, client2 来自: 127.0.0.1:63776
发送消息: hi, client2 目的地: 127.0.0.1:63777
收到消息: 127.0.0.1:63777&list 来自: 127.0.0.1:63777
发送消息: ||||127.0.0.1:63776||||127.0.0.1:63777 目的地: 127.0.0.1:63777
收到消息: 127.0.0.1:63776#hi, client1 来自: 127.0.0.1:63777
发送消息: hi, client1 目的地: 127.0.0.1:63776
收到消息: exit 来自: 127.0.0.1:63776
客户端: 127.0.0.1:63776 正在退出...
客户端列表:
--------------------
127.0.0.1:63777
收到消息: exit 来自: 127.0.0.1:63777
客户端: 127.0.0.1:63777 正在退出...
客户端列表:
--------------------

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

client1:

客服端正在建立连接...
客户端成功连接到服务端, 服务端地址: 127.0.0.1:8888
127.0.0.1:63776&list
发送消息: 127.0.0.1:63776&list
收到消息: ||||127.0.0.1:63776||||127.0.0.1:63777
127.0.0.1:63777#hi, client2
发送消息: 127.0.0.1:63777#hi, client2
收到消息: hi, client1
exit
发送消息: exit
客户端关闭

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

client2:

客服端正在建立连接...
客户端成功连接到服务端, 服务端地址: 127.0.0.1:8888
收到消息: hi, client2
127.0.0.1:63777&list
发送消息: 127.0.0.1:63777&list
收到消息: ||||127.0.0.1:63776||||127.0.0.1:63777
127.0.0.1:63776#hi, client1
发送消息: 127.0.0.1:63776#hi, client1
exit
发送消息: exit
客户端关闭

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

日志

2021/08/27 01:08:04 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:209: 写入日志, 服务器正在启动...

2021/08/27 01:08:07 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:231: 服务端连接到客服端, 客户端地址: 127.0.0.1:63776

2021/08/27 01:08:07 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:242: 客户端列表:
---------------------------------------------------

2021/08/27 01:08:07 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:245: 127.0.0.1:63776

2021/08/27 01:08:09 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:231: 服务端连接到客服端, 客户端地址: 127.0.0.1:63777

2021/08/27 01:08:09 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:242: 客户端列表:
---------------------------------------------------

2021/08/27 01:08:09 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:245: 127.0.0.1:63776

2021/08/27 01:08:09 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:245: 127.0.0.1:63777

2021/08/27 01:08:20 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:135: 收到消息: 127.0.0.1:63776&list 来自: 127.0.0.1:63776

2021/08/27 01:08:20 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:104: 发送消息: ||||127.0.0.1:63776||||127.0.0.1:63777 目的地: 127.0.0.1:63776

2021/08/27 01:08:31 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:135: 收到消息: 127.0.0.1:63777#hi, client2 来自: 127.0.0.1:63776

2021/08/27 01:08:42 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:135: 收到消息: 127.0.0.1:63777&list 来自: 127.0.0.1:63777

2021/08/27 01:08:42 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:104: 发送消息: ||||127.0.0.1:63776||||127.0.0.1:63777 目的地: 127.0.0.1:63777

2021/08/27 01:08:53 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:135: 收到消息: 127.0.0.1:63776#hi, client1 来自: 127.0.0.1:63777

2021/08/27 01:09:04 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:135: 收到消息: exit 来自: 127.0.0.1:63776

2021/08/27 01:09:04 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:142: 客户端: 127.0.0.1:63776 正在退出...

2021/08/27 01:09:04 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:168: 客户端列表:
--------------------

2021/08/27 01:09:11 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:135: 收到消息: exit 来自: 127.0.0.1:63777

2021/08/27 01:09:11 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:142: 客户端: 127.0.0.1:63777 正在退出...

2021/08/27 01:09:11 C:/Users/Windows/Desktop/project2/chat_room/server2/server.go:168: 客户端列表:
--------------------

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

在这里插入图片描述

文章来源: iamarookie.blog.csdn.net,作者:我是小白呀,版权归原作者所有,如需转载,请联系作者。

原文链接:iamarookie.blog.csdn.net/article/details/119881442

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。