niyuelin1990的博客

专注区块链,云原生,中间件技术

golang tcp 客户端

最近找了网上tcp客户端的例子,都不是很好,特今天写一个tcp 客户端案例。


1.新建tcpclient结构体:

type TcpClientModel struct {
       Conn net.Conn
       //发送chan
       SendChan chan []byte
       //心跳chan
       ClientPingChan chan int
       //停止chan
       StopChan        chan int
}


2. 链接服务器:

//连接服务器
func connectServers() {
       conn, err := net.Dial("tcp", "10.7.28.130:9998")
       if err != nil {
              log.Println(err)
              return
       }
       defer conn.Close()
       tcpClientM := &TcpClientModel{
              Conn:            conn,
              StopChan:        make(chan int, 1),
              ClientPingChan:  make(chan int, 100),
              SendChan:        make(chan []byte, 100),
       }
       tc0 = tcpClientM
       go tcpClientM.pingAndDataPacket()
       tcpClientM.receivePackets()
}


3.发送心跳和数据包接口

//发送心跳和数据包
func (tcpClient *TcpClientModel) pingAndDataPacket() {
       for {
              select {
              //数据发送统一接口
              case data, _ := <-tcpClient.SendChan:
                     tcpClient.Conn.Write(data)
                     //定时发送心跳数据
              case <-time.Tick(10 * time.Second):
                     tcpClient.sendHeartPacket()
                     //防止心跳发送chan
              case <-tcpClient.ClientPingChan:
              case <-tcpClient.StopChan:
                     goto stop
              }
       }
stop:
       log.Println("关闭连接")
}
func (tcpClient *TcpClientModel) sendHeartPacket() {
       //ping 包数据
       tcpClient.Conn.Write([]byte{})
}


4. 接受服务端数据并处理业务

func (tcpClient *TcpClientModel) receivePackets() {
       defer func() {
              log.Println("close tcpClient")
              tcpClient.StopChan <- 1
              tcpClient.Conn.Close()
              if err := recover(); err != nil {
                     log.Println("readPacket", zap.Any("recover", err))
                     return
              }
       }()
       //接受服务端数据并处理业务
       for {
              message, err := proto.ReadPacket(tcpClient.Conn)
              if err != nil {
                     log.Println("packet is get error", zap.Error(err))
                     goto LogOut
              }
              switch m := message.(type) {
              case *proto.StreamPongPacket:
                     log.Println("业务处理, 可以新开携程去处理",m)
              default:
                     log.Println("invalid messageReceived msg:", zap.Any("message", message))
                     goto LogOut
              }
       }
LogOut:
       log.Println("关闭链接")
}

5. 函数入口,数据发送

func main() {
       go connectServers()
       time.Sleep(time.Second * 1)

       tc.SendChan <- []byte{1, 2, 1, 2}
       //tc.sendHeartPacket()

       time.Sleep(time.Second * 20)
       tc.SendChan <- []byte{1, 2, 1, 2}
       select {}

}

总结: 1.  message, err := proto.ReadPacket(tcpClient.Conn)  接受服务端数据有可以单独开携程去接受,并通过chan到业务处理方法

2.退出 tcpclient的时候必须关闭pingAndDataPacket 携程

3. 若有数据接受,且不往服务端回复数据的话,可以往ClientPingChan 发送信号,防止反复发送心跳数据

4.  proto.ReadPacket(tcpClient.Conn)  数据处理  采用如下方式“var b = make([]byte, TCP_MAX_PACKET_SIZE)   _, err := conn.Read(b[:2])“


阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/niyuelin1990/article/details/77868574
文章标签: tcp
个人分类: go
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

golang tcp 客户端

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭