go语言实现聊天服务器的示例代码
看了两天go语言,是时候练练手了。
go的routine(例程)和chan(通道)简直是神器,实现多线程(在go里准确的来说是多例程)简直不要太轻松。
于是动手码了一个傻瓜版的黑框聊天器。
server端:
监听TCP连接;支持自定义客户端命令;支持消息分发;理论上支持广播;...
packagemain import( "fmt" "net" "io" "strconv" "time" "strings" ) const( NORMAL_MESSAGE=iota LIST_MESSAGE ) varclientSenders=make(map[string]chanstring) funcsend(addrstring,conn*net.Conn){ senderChan:=clientSenders[addr] fors:=rangesenderChan{ (*conn).Write([]byte(s)) } } funcsendUsersInfo(addrstring){ senderChan:=clientSenders[addr] ifnil!=senderChan{ ls:=strconv.Itoa(LIST_MESSAGE) cs:=strconv.Itoa(NORMAL_MESSAGE)+"已登录客户端列表:\n" i:=1 fork:=rangeclientSenders{ a:="" ifk==addr{ a="(我)" } cs=cs+strconv.Itoa(i)+")"+k+a+"\n" ls+=k+"\n" i++ } cs+="发送消息,可使用1<-这是给1号客户端的消息\n(请使用英文以获取最佳体验)\n" senderChan<-cs time.Sleep(time.Millisecond*300) senderChan<-ls //发送格式化的列表 fmt.Println("已发送“登录用户信息”",addr) }else{ fmt.Println("客户端接受通道不存在",addr) } } funcserve(conn*net.Conn){ connect:=*conn addr:=connect.RemoteAddr().String() fmt.Println(addr,"接入服务") senderChan:=make(chanstring,3) clientSenders[addr]=senderChan //启动发送 gosend(addr,conn) //发送当前用户信息 gosendUsersInfo(addr) buff:=make([]byte,10240) for{ n,err:=connect.Read(buff) iferr!=nil{ iferr==io.EOF{ fmt.Println("客户端断开链接,",addr) delete(clientSenders,addr) return }else{ fmt.Println(err) } } msg:=string(buff[:n]) //刷新客户端列表 ifmsg=="ls\n"{ gosendUsersInfo(addr) continue } //提取数据 msgs:=strings.Split(msg,"<-") iflen(msg)<2{ senderChan<-string("数据格式不正确,请联系开发者") continue } aimAddr:=msgs[0] aimSender:=clientSenders[aimAddr] ifaimSender==nil{ senderChan<-string("客户端已下线,使用ls命令获取最新的客户端列表") continue } aimSender<-strconv.Itoa(NORMAL_MESSAGE)+"[from:"+addr+"]:"+strings.Join(msgs[1:],"<-") } } funcmain(){ addr:=":8080" listener,err:=net.Listen("tcp",addr) iferr!=nil{ fmt.Println(err) return } //启动消息调度器 deferlistener.Close() //启动连接监听 for{ conn,err:=listener.Accept() iferr!=nil{ fmt.Println(err) continue } goserve(&conn) } }
客户端:
支持断线重连;支持给特定其他客户端发信息
packagemain import( "net" "fmt" "io" "os" "bufio" "sync" "time" "strings" "strconv" ) varconn*net.Conn varaddrs[]string const( NORMAL_MESSAGE=iota LIST_MESSAGE ) funcread(conn2*net.Conn){ deferfunc(){ fmt.Println("尝试重连") goconnectServer() }() connect:=*conn2 buff:=make([]byte,20140) for{ n,err:=connect.Read(buff) iferr!=nil{ iferr==io.EOF{ fmt.Println("结束") (*conn2).Close() conn=nil return }else{ fmt.Println(err) } } msg:=string(buff[:n]) t,err:=strconv.Atoi(string(msg[0])) msg=msg[1:] switcht{ caseNORMAL_MESSAGE: fmt.Print(msg) break caseLIST_MESSAGE: //解析客户端列表数据 addrs=strings.Split(msg,"\n") fmt.Println("已接收客户端列表。\n") break default: fmt.Print(msg) break } } } funcconnectServer(){ addr:="192.168.99.236:8080" fmt.Println("等待服务器开启中") conn2,err:=net.Dial("tcp",addr) iferr!=nil{ fmt.Print(err) fmt.Println("连接失败,10s后尝试") time.Sleep(10*time.Second) goconnectServer() return } fmt.Println("已连接") conn=&conn2 goread(&conn2) } funcsend(){ inputReader:=bufio.NewReader(os.Stdout) for{ input,err:=inputReader.ReadString('\n') iferr!=nil{ iferr==io.EOF{ return }else{ fmt.Println(err) } } ifinput=="ls\n"{ (*conn).Write([]byte(input)) continue } msgs:=strings.Split(input,"<-") iflen(msgs)<2{ fmt.Println("发送的姿势不正确,应该像这样1<-给1号发送消息\n") continue } index,err:=strconv.Atoi(msgs[0]) iferr!=nil{ fmt.Println("发送的姿势不正确,应该像这样1<-给1号发送消息\n") continue } iflen(addrs)<=index{ fmt.Println("不存在第"+strconv.Itoa(index)+"个客户端\n") continue } addr:=addrs[index-1] input=addr+"<-"+strings.Join(msgs[1:],"<-") ifnil!=conn{ (*conn).Write([]byte(input)) } } } funcmain(){ varwgsync.WaitGroup wg.Add(2) goconnectServer() gosend() wg.Wait() deferfunc(){ ifnil!=conn{ (*conn).Close() } }() }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。