golang對併發的支持很是好,就是由於他有一個goroutine機制和channel機制,實現併發場景輕鬆高效。python
下面咱們實現一個聊天室程序,代碼很少,可是功能很強大golang
//代碼轉載自:http://blog.csdn.net/ygrx/article/details/11773151 package main import ( "fmt" "net" "os" ) //////////////////////////////////////////////////////// // //錯誤檢查 // //////////////////////////////////////////////////////// func checkError(err error, info string) (res bool) { if err != nil { fmt.Println(info + " " + err.Error()) return false } return true } //////////////////////////////////////////////////////// // //服務器端接收數據線程 //參數: // 數據鏈接 conn // 通信通道 messages // //////////////////////////////////////////////////////// func Handler(conn net.Conn, messages chan string) { fmt.Println("connection is connected from ...", conn.RemoteAddr().String()) buf := make([]byte, 1024) for { lenght, err := conn.Read(buf) if checkError(err, "Connection") == false { conn.Close() break } if lenght > 0 { buf[lenght] = 0 } //fmt.Println("Rec[",conn.RemoteAddr().String(),"] Say :" ,string(buf[0:lenght])) reciveStr := string(buf[0:lenght]) messages <- reciveStr } } //////////////////////////////////////////////////////// // //服務器發送數據的線程 // //參數 // 鏈接字典 conns // 數據通道 messages // //////////////////////////////////////////////////////// func echoHandler(conns *map[string]net.Conn, messages chan string) { for { msg := <-messages fmt.Println(msg) for key, value := range *conns { fmt.Println("connection is connected from ...", key) _, err := value.Write([]byte(msg)) if err != nil { fmt.Println(err.Error()) delete(*conns, key) } } } } //////////////////////////////////////////////////////// // //啓動服務器 //參數 // 端口 port // //////////////////////////////////////////////////////// func StartServer(port string) { service := ":" + port //strconv.Itoa(port); tcpAddr, err := net.ResolveTCPAddr("tcp4", service) checkError(err, "ResolveTCPAddr") l, err := net.ListenTCP("tcp", tcpAddr) checkError(err, "ListenTCP") conns := make(map[string]net.Conn) messages := make(chan string, 10) //啓動服務器廣播線程 go echoHandler(&conns, messages) for { fmt.Println("Listening ...") conn, err := l.Accept() checkError(err, "Accept") fmt.Println("Accepting ...") conns[conn.RemoteAddr().String()] = conn //啓動一個新線程 go Handler(conn, messages) } } //////////////////////////////////////////////////////// // //客戶端發送線程 //參數 // 發送鏈接 conn // //////////////////////////////////////////////////////// func chatSend(conn net.Conn) { var input string username := conn.LocalAddr().String() for { fmt.Scanln(&input) if input == "/quit" { fmt.Println("ByeBye..") conn.Close() os.Exit(0) } lens, err := conn.Write([]byte(username + " Say :::" + input)) fmt.Println(lens) if err != nil { fmt.Println(err.Error()) conn.Close() break } } } //////////////////////////////////////////////////////// // //客戶端啓動函數 //參數 // 遠程ip地址和端口 tcpaddr // //////////////////////////////////////////////////////// func StartClient(tcpaddr string) { tcpAddr, err := net.ResolveTCPAddr("tcp4", tcpaddr) checkError(err, "ResolveTCPAddr") conn, err := net.DialTCP("tcp", nil, tcpAddr) checkError(err, "DialTCP") //啓動客戶端發送線程 go chatSend(conn) //開始客戶端輪訓 buf := make([]byte, 1024) for { lenght, err := conn.Read(buf) if checkError(err, "Connection") == false { conn.Close() fmt.Println("Server is dead ...ByeBye") os.Exit(0) } fmt.Println(string(buf[0:lenght])) } } //////////////////////////////////////////////////////// // //主程序 // //參數說明: // 啓動服務器端: Chat server [port] eg: Chat server 9090 // 啓動客戶端: Chat client [Server Ip Addr]:[Server Port] eg: Chat client 192.168.0.74:9090 // //////////////////////////////////////////////////////// func main() { fmt.Println(os.Args) if len(os.Args) != 3 { fmt.Println("Wrong pare") os.Exit(0) } if os.Args[1] == "server" && len(os.Args) == 3 { StartServer(os.Args[2]) } if os.Args[1] == "client" && len(os.Args) == 3 { StartClient(os.Args[2]) } }
只須要在命令行輸入例如:go run main.go server 9000 這樣的命令,就能夠開啓服務端監聽。服務器
假設server的ip爲192.168.1.3,那麼輸入:go run main.go client 192.168.1.3:9000便可鏈接到服務器並進入聊天室。併發