Codeforces 1381B Unmerge(01揹包)
阿新 • • 發佈:2020-08-04
Go語言實踐_實現一(伺服器端)對多(客戶端)線上聊天室
目的
運用Go語言中的goroutine和通道實現一個簡單的一個伺服器端對多個客戶端的線上聊天
設計思路
與一對一的設計思路類似,就是加了個執行緒的操作。
1,伺服器端宣告一個map,並開啟監聽埠;
2,客戶端開啟監聽埠,同時連入伺服器端;
3,在客戶端上給自己起一個暱稱,並輸出,同時啟動一個執行緒;
4,伺服器端接收一個暱稱,並存入map;
5,宣告一個空的字串,並寫入要群發的訊息;
6,伺服器端解析傳送的訊息(msg_str[0]的值):
nick:使該客戶端加入聊天室並廣播連上伺服器端的所有其他客戶端;
say:廣播客戶端發出的訊息;
程式碼
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