从零开始写Go网络通信框架(3)——对长连接的处理
来源:互联网 发布:linux 日志重定向 编辑:程序博客网 时间:2024/06/01 10:25
我要写的这个通讯框架,主要用于监控。那么就会有多个客户端建立不关闭的长连接,这对服务端的开销是很大的。
我这里对长连接的处理方式是:Server端收到Client端发来的信息之后,开始心跳计时,在设定时间内如果收到Client发来的消息,则重置计时器,否则计时结束断开连接。
在Client端,我的处理方式是:用time.NewTicker创建一个定时器,每间隔一秒发送下当前时间到服务器。为简便起见,未做信号中断,这个我们后续再完善。
Server端核心代码为:
//解包tmpbuf = protocol.Depack(append(tmpbuf,buf[:n]...))fmt.Println("client say:",string(tmpbuf))Msg:=tmpbufbeatch :=make(chan byte)//心跳计时,默认30秒go HeartBeat(conn,beatch,30)//检测每次Client是否有数据传来go HeartChanHandler(Msg,beatch)
解包成功后添加心跳计时,并用HeartChanHandler来检测Client是否有数据出来。完整代码如下:
package mainimport ("fmt""os""net""log""github.com/mxi4oyu/MoonSocket/protocol""time")//定义CheckError方法,避免写太多到 if err!=nilfunc CheckError(err error) {if err!=nil{fmt.Fprintf(os.Stderr,"Fatal error:%s",err.Error())os.Exit(1)}}//自定义logfunc Log(v... interface{}) {log.Println(v...)}func main() { server_listener,err:=net.Listen("tcp","localhost:8848")CheckError(err)defer server_listener.Close()Log("Waiting for clients connect")for{new_conn,err:=server_listener.Accept()CheckError(err)go ServerMsgHandler(new_conn)}}//服务端消息处理func ServerMsgHandler(conn net.Conn) {//存储被截断的数据tmpbuf:=make([] byte,0)buf:=make([] byte,1024)defer conn.Close()//接收解包readchan:=make(chan [] byte,16)go ReadChan(readchan)for{n,err:=conn.Read(buf)if err!=nil{fmt.Println("connection close")return}//解包tmpbuf = protocol.Depack(append(tmpbuf,buf[:n]...))fmt.Println("client say:",string(tmpbuf))Msg:=tmpbufbeatch :=make(chan byte)//心跳计时,默认30秒go HeartBeat(conn,beatch,30)//检测每次Client是否有数据传来go HeartChanHandler(Msg,beatch)}}//处理心跳,根据HeartChanHandler判断Client是否在设定时间内发来信息func HeartBeat(conn net.Conn,heartChan chan byte,timeout int) {select {case hc:=<-heartChan:Log("<-heartChan:",string(hc))conn.SetDeadline(time.Now().Add(time.Duration(timeout)*time.Second))breakcase <-time.After(time.Second*30):Log("timeout")conn.Close()}}//处理心跳channelfunc HeartChanHandler( n [] byte,beatch chan byte) {for _,v:=range n{beatch<-v}close(beatch)}//从channell中读取数据func ReadChan(readchan chan [] byte) {for{select {case data:=<-readchan:Log(string(data))}}}
我在Client端也做了一些代码调整,主要是在main方法中添加计时器,并用ClientMsgHandler处理客户端的消息,核心代码如下:
ticker := time.NewTicker(time.Second)defer ticker.Stop()for{select {case <-ticker.C:ch<-1go ClientMsgHandler(conn,ch)case <-time.After(time.Second*10):defer conn.Close()fmt.Println("timeout")}}
完整代码如下:
package mainimport ("fmt""os""net""strconv""time""github.com/mxi4oyu/MoonSocket/protocol")//定义CheckError方法,避免写太多到 if err!=nilfunc CheckError(err error) {if err!=nil{fmt.Fprintf(os.Stderr,"Fatal error:%s",err.Error())os.Exit(1)}}func main() {if len(os.Args) !=2 {fmt.Fprintf(os.Stderr,"Usage:%s IP:Port\n",os.Args[0])os.Exit(1)}//动态传入服务端IP和端口号service:=os.Args[1]tcpAddr,err:=net.ResolveTCPAddr("tcp4",service)CheckError(err)conn,err:=net.DialTCP("tcp",nil,tcpAddr)CheckError(err)ch:=make(chan int,100)ticker := time.NewTicker(time.Second)defer ticker.Stop()for{select {case <-ticker.C:ch<-1go ClientMsgHandler(conn,ch)case <-time.After(time.Second*10):defer conn.Close()fmt.Println("timeout")}}}//客户端消息处理func ClientMsgHandler(conn net.Conn,ch chan int) {<-ch//获取当前时间msg:=time.Now().String()SendMsg(conn,msg)}func GetSession() string{gs1:=time.Now().Unix()gs2:=strconv.FormatInt(gs1,10)return gs2}func SendMsg(conn net.Conn,msg string) {session:=GetSession()words := "{\"Session\":"+session +",\"Meta\":\"Monitor\",\"Message\":\""+msg+"\"}"conn.Write([] byte(words))protocol.Enpack([]byte(words))conn.Write(protocol.Enpack([]byte(words)))}
阅读全文
1 0
- 从零开始写Go网络通信框架(3)——对长连接的处理
- 从零开始写Go网络通信框架(2)——自定义通讯协议
- 从零开始写Go网络通信框架(4)——全双工收发消息
- 从零开始写Go网络通信框架(5)——断线重连
- 从零开始写Go网络通信框架(1)——基本的Socket Client/Server的编写
- [Golang] 从零开始写Socket Server(3): 对长、短连接的处理策略(模拟心跳)
- Android长连接--网络框架之mina框架的解析
- socket、长连接、自定义消息体的网络通信
- go实现一个简单的游戏服务器框架(lotou)网络通信
- cocos2dx长连接BSDSocke网络通信
- go 短连接和长连接 超时处理
- 从零开始写javaweb框架(第一章)—— 所遇到的问题 与 解决方法
- 从零开始写javaweb框架(第二章)—— 所遇到的问题 与 解决方法
- 从零开始学android:Android事件处理—长按事件
- go net/http Client使用——长连接客户端的使用
- 通信长连接并包头+包长处理方式
- 【Android】自己写的轻量级安卓网络框架——能够控制网络连接,支持缓存
- 网络通信中的长连接和短连接
- 火狐浏览器:This Connection is not Secure
- 窗体部件之QButtonGroup
- React-navigator之TabNavigtion2
- Spring框架JdbcTemplate类中查询方法介绍
- 数组---一维数组
- 从零开始写Go网络通信框架(3)——对长连接的处理
- 在mysql上使用存储过程给相应的表加入字段
- 计算机图形学之光线跟踪算法的研究与实现2017年我的优秀毕业论文
- Wineskin
- box-sizing
- 添加第三方库
- hadoop集群之间的文件拷贝——distcp
- 将sklearn生成的决策树进行图形化展示
- mysql中int、bigint、smallint 和 tinyint的区别与长度的含义