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()
}
}()
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。