最近找了网上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])“