【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
客服
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。