這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
最近看了一下go語言,就試著寫了一個聊天室,練練手而已,但是對於我一個搞php的來說,go語言對我啟發很大。
客服端
package mainimport ( "fmt" "net" "os")//定義通道var ch chan int = make(chan int)//定義暱稱var nickname stringfunc 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, 下一個輸入就沒有法進行 } }
伺服器端
package mainimport ( "fmt" "net")var ConnMap map[string]*net.TCPConnfunc 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) }}