最近看了一下go语言,就试着写了一个聊天室,练练手而已,但是对于我一个搞PHP的来说,go语言对我启发很大。
客服端
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, 下一个输入就没有法进行 } }
服务器端
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,"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) } }