1. 程式人生 > 實用技巧 >Codeforces 1381B Unmerge(01揹包)

Codeforces 1381B Unmerge(01揹包)

Go語言實踐_實現一(伺服器端)對多(客戶端)線上聊天室

目的

運用Go語言中的goroutine和通道實現一個簡單的一個伺服器端對多個客戶端的線上聊天

設計思路

與一對一的設計思路類似,就是加了個執行緒的操作。

1,伺服器端宣告一個map,並開啟監聽埠;

2,客戶端開啟監聽埠,同時連入伺服器端;

3,在客戶端上給自己起一個暱稱,並輸出,同時啟動一個執行緒;

4,伺服器端接收一個暱稱,並存入map;

5,宣告一個空的字串,並寫入要群發的訊息;

6,伺服器端解析傳送的訊息(msg_str[0]的值):

nick:使該客戶端加入聊天室並廣播連上伺服器端的所有其他客戶端;
say:廣播客戶端發出的訊息;

quit:使該客戶端退出,斷開與伺服器端的連線,並將退出訊息廣播給其他連上伺服器端的所有其他客戶端;

程式碼

server.go

 1 // one sever to more client chat room
 2 //This is chat sever
 3 package main
 4 
 5 import (
 6     "fmt"
 7     "net"
 8     "strings"
 9 )
10 
11 var ConnMap map[string]net.Conn = make(map[string]net.Conn)  //宣告一個集合
12 
13 //ConnMap := make(map[string]net.Conn)
14 15 func main() { 16 listen_socket, err := net.Listen("tcp", "127.0.0.1:8000") //開啟監聽介面 17 if err != nil { 18 fmt.Println("server start error") 19 } 20 21 defer listen_socket.Close() 22 fmt.Println("server is wating ....") 23 24 for { 25 conn, err := listen_socket.Accept() //
收到來自客戶端發來的訊息 26 if err != nil { 27 fmt.Println("conn fail ...") 28 } 29 fmt.Println(conn.RemoteAddr(), "connect successed") 30 31 go handle(conn) //建立執行緒 32 } 33 } 34 35 func handle(conn net.Conn) { 36 for { 37 data := make([]byte, 255) //建立位元組流 (此處同 一對一 通訊) 38 msg_read, err := conn.Read(data) //宣告並將從客戶端讀取的訊息賦給msg_read 和err 39 if msg_read == 0 || err != nil { 40 continue 41 } 42 43 //解析協議 44 msg_str := strings.Split(string(data[0:msg_read]), "|") //將從客戶端收到的位元組流分段儲存到msg_str這個陣列中 45 46 switch msg_str[0] { 47 case "nick": //加入聊天室 48 fmt.Println(conn.RemoteAddr(), "-->", msg_str[1]) //nick佔在陣列下標0上,客戶端上寫的暱稱佔在陣列下標1上 49 for k, v := range ConnMap { //遍歷集合中儲存的客戶端訊息 50 if k != msg_str[1] { 51 v.Write([]byte("[" + msg_str[1] + "]: join...")) 52 } 53 } 54 ConnMap[msg_str[1]] = conn 55 case "say": //轉發訊息 56 for k, v := range ConnMap { //k指客戶端暱稱 v指客戶端連線伺服器端後的地址 57 if k != msg_str[1] { //判斷是不是給自己發,如果不是 58 fmt.Println("Send "+msg_str[2]+" to ", k) //伺服器端將訊息轉發給集合中的每一個客戶端 59 v.Write([]byte("[" + msg_str[1] + "]: " + msg_str[2])) //給除了自己的每一個客戶端傳送自己之前要傳送的訊息 60 } 61 } 62 case "quit": //退出 63 for k, v := range ConnMap { //遍歷集合中的客戶端暱稱 64 if k != msg_str[1] { //如果暱稱不是自己 65 v.Write([]byte("[" + msg_str[1] + "]: quit")) //給除了自己的其他客戶端暱稱傳送退出的訊息,並使Write方法阻塞 66 } 67 } 68 delete(ConnMap, msg_str[1]) //退出聊天室 69 } 70 } 71 }

client.go

 1 // one sever to more client chat room
 2 //This is chat client
 3 package main
 4 
 5 import (
 6     "fmt"
 7     "net"
 8 )
 9 
10 var nick string = "" //宣告聊天室的暱稱
11 
12 func main() {
13     conn, err := net.Dial("tcp", "127.0.0.1:8000") //開啟監聽埠
14     if err != nil {
15         fmt.Println("conn fail...")
16     }
17     defer conn.Close()
18     fmt.Println("client connect server successed \n")
19 
20     //給自己取一個聊天室的暱稱
21     fmt.Printf("Make a nickname:")
22     fmt.Scanf("%s", &nick)             //輸入暱稱
23     fmt.Println("hello : ", nick)      //客戶端輸出
24     conn.Write([]byte("nick|" + nick)) //將資訊傳送給伺服器端
25 
26     go Handle(conn) //建立執行緒
27 
28     var msg string
29     for {
30         msg = ""                                      //宣告一個空的訊息
31         fmt.Scan(&msg)                                //輸入訊息
32         conn.Write([]byte("say|" + nick + "|" + msg)) //三段位元組流 say | 暱稱 | 傳送的訊息
33         if msg == "quit" {                            //如果訊息為quit
34             conn.Write([]byte("quit|" + nick)) //將quit位元組流傳送給伺服器端
35             break                              //程式結束執行
36         }
37     }
38 }
39 
40 func Handle(conn net.Conn) {
41 
42     for {
43 
44         data := make([]byte, 255)        //建立一個位元組流
45         msg_read, err := conn.Read(data) //將讀取的位元組流賦值給msg_read和err
46         if msg_read == 0 || err != nil { //如果位元組流為0或者有錯誤
47             break
48         }
49 
50         fmt.Println(string(data[0:msg_read])) //把位元組流轉換成字串
51     }
52 }

編譯執行服務端與客戶端

go run server.go
go run client.go

執行結果展示

轉載自:https://blog.csdn.net/qq_43569535/article/details/104224976