长连接的处理方式是:
Server端收到Client端发来的信息之后,开始心跳计时,在设定时间内如果收到Client发来的消息,则重置计时器,否则计时结束断开连接。
Client端,处理方式是:用time.NewTicker创建一个定时器,每间隔一秒发送下当前时间到服务器。
服务端代码如下:
- package main
- import (
- "fmt"
- "os"
- "net"
- "log"
- "github.com/mxi4oyu/MoonSocket/protocol"
- "time"
- )
- //定义CheckError方法,避免写太多到 if err!=nil
- func CheckError(err error) {
- if err!=nil{
- fmt.Fprintf(os.Stderr,"Fatal error:%s",err.Error())
- os.Exit(1)
- }
- }
- //自定义log
- func 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:=tmpbuf
- beatch :=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))
- break
- case <-time.After(time.Second*30):
- Log("timeout")
- conn.Close()
- }
- }
- //处理心跳channel
- func 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))
- }
- }
- }
客户端代码如下:
- package main
- import (
- "fmt"
- "os"
- "net"
- "strconv"
- "time"
- "github.com/mxi4oyu/MoonSocket/protocol"
- )
- //定义CheckError方法,避免写太多到 if err!=nil
- func 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<-1
- go 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)))
- }