最近看了一下go語言,就試着寫了一個聊天室,練練手而已,可是對於我一個搞php的來講,go語言對我啓發很大。php
客服端服務器
package main import ( "fmt" "net" "os" ) //定義通道 var ch chan int = make(chan int) //定義暱稱 var nickname string func reader(conn *net.TCPConn) { buff := make([]byte, 128) for { j, err := conn.Read(buff) if err != nil { ch <- 1 break } fmt.Println(string(buff[0:j])) } } func main() { tcpAddr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:9999") conn, err := net.DialTCP("tcp", nil, tcpAddr) if err != nil { fmt.Println("Server is not starting") os.Exit(0) } //爲何不能放到if以前? err不爲nil的話就是painc了 (painc 與 defer 辨析一下!!!) defer conn.Close() go reader(conn) fmt.Println("請輸入暱稱") fmt.Scanln(&nickname) fmt.Println("你的暱稱爲:", nickname) for { var msg string fmt.Scanln(&msg) b := []byte("<" + nickname + ">" + "說:" + msg) conn.Write(b) //select 爲非阻塞的 select { case <-ch: fmt.Println("Server錯誤!請從新鏈接!") os.Exit(1) default: //不加default的話,那麼 <-ch 會阻塞for, 下一個輸入就沒有法進行 } }
服務器端tcp
package main import ( "fmt" "net" ) var ConnMap map[string]*net.TCPConn func checkErr(err error) int { if err != nil { if err.Error() == "EOF" { //用戶退出 fmt.Println("用戶推出了") return 0 } fmt.Println("錯誤") return -1 } return 1 } func say(tcpConn *net.TCPConn) { for { //讀取一個客戶端發送過來的數據 data := make([]byte, 128) total, err := tcpConn.Read(data) fmt.Println(string(data[:total]), err) flag := checkErr(err) if flag == 0 { //退出整個循環 break } //廣播形式,向各個客戶端發送數據 for _, conn := range ConnMap { if conn.RemoteAddr().String() == tcpConn.RemoteAddr().String() { //不向數據輸入的客戶端發送消息 continue } conn.Write(data[:total]) } } } func main() { tcpAddr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:9999") tcpListener, _ := net.ListenTCP("tcp", tcpAddr) /* map 定義完後,還要make? (哪些數據類型定義完後,還要make?) http://stackoverflow.com/questions/27267900/runtime-error-assignment-to-entry-in-nil-map */ ConnMap = make(map[string]*net.TCPConn) for { tcpConn, _ := tcpListener.AcceptTCP() defer tcpConn.Close() ConnMap[tcpConn.RemoteAddr().String()] = tcpConn fmt.Println("鏈接的客服端信息:", tcpConn.RemoteAddr().String()) go say(tcpConn) } }