项目地址
https://github.com/mangenotwork/CLI-Sichuan-Mahjong
数据传输结构定义
这里使用gob序列化数据
// entity.go
type TransfeData struct {
Cmd enum.Command // 指令
Timestamp int64
Token string // 识别客户端身份
Data interface{} // 传输的数据
Message string // 传输消息
Code int // 传输code
}
func (t *TransfeData) Byte() []byte {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err := enc.Encode(t)
if err != nil {
log.Fatal("encode error:", err)
}
return buf.Bytes()
}
func NewTransfeData(cmd enum.Command, token string, data interface{}) []byte {
tra := &TransfeData{
Cmd: cmd,
Timestamp: time.Now().Unix(),
Token: token,
Data: data,
}
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err := enc.Encode(tra)
if err != nil {
log.Fatal("encode error:", err)
}
return buf.Bytes()
}
func TransfeDataDecoder(data []byte) *TransfeData {
buf := bytes.NewBuffer(data)
dec := gob.NewDecoder(buf)
tra := &TransfeData{}
err := dec.Decode(&tra)
if err != nil {
log.Fatal("decode error:", err)
}
return tra
}
Server 端
// tcp
type TcpServer struct {
Listener *net.TCPListener
HawkServer *net.TCPAddr
}
// 运行服务
func Run() {
//类似于初始化套接字,绑定端口
hawkServer, err := net.ResolveTCPAddr("tcp", "0.0.0.0:14444")
if err != nil {
panic(err)
}
//侦听
listen, err := net.ListenTCP("tcp", hawkServer)
utils.PanicErr(err)
//关闭
defer listen.Close()
tcpServer := &TcpServer{
Listener: listen,
HawkServer: hawkServer,
}
log.Println("start Master TCP server successful.")
//接收请求
for {
//来自客户端的连接
conn, err := tcpServer.Listener.Accept()
if err != nil {
log.Println("[连接失败]:", err.Error())
continue
}
log.Println("[连接成功]: ", conn.RemoteAddr().String(), conn)
go func(conn net.Conn){
// 最大接收1024个字节
recv := make([]byte, 1024)
// 设置读取超时
err = conn.SetReadDeadline(time.Now().Add(60*time.Second)) // timeout
if err != nil {
log.Println("setReadDeadline failed:", err)
}
for {
// 接收数据
n, err := conn.Read(recv)
if err != nil{
// 处理断开连接
if err == io.EOF {
log.Println(conn.RemoteAddr().String(), " 断开了连接!")
conn.Close()
return
}
}
// 打印接收的数据
if n > 0 && n < 1025 {
data := entity.TransfeDataDecoder(recv[:n])
log.Println(data)
}
}
}(conn)
}
}
Client端
// 重连chan
var RConn = make(chan bool)
type TcpClient struct {
Connection *net.TCPConn
HawkServer *net.TCPAddr
StopChan chan struct{} // 停止 chan
CmdChan chan *entity.TransfeData // 来自Server数据传输chan
}
func (c *TcpClient) Send(b []byte) (int, error) {
return c.Connection.Write(b)
}
func (c *TcpClient) Read(b []byte) (int, error) {
return c.Connection.Read(b)
}
func (c *TcpClient) Addr() string {
return c.Connection.RemoteAddr().String()
}
func (c *TcpClient) Close(){
c.Connection.Close()
RConn <- true
}
func Run(){
//用于重连
Reconnection:
host := "192.168.0.9:14444"
hawkServer, err := net.ResolveTCPAddr("tcp", host)
if err != nil {
log.Printf("hawk server [%s] resolve error: [%s]", host, err.Error())
time.Sleep(1 * time.Second) //连接失败后1秒重连
goto Reconnection
}
//连接服务器
connection, err := net.DialTCP("tcp", nil, hawkServer)
if err != nil {
log.Printf("connect to hawk server error: [%s]", err.Error())
time.Sleep(1 * time.Second)
goto Reconnection
}
log.Println("[连接成功] 连接服务器成功")
//创建客户端实例
client := &TcpClient{
Connection: connection,
HawkServer: hawkServer,
StopChan: make(chan struct{}),
CmdChan: make(chan *entity.TransfeData),
}
//启动接收
go func(conn *models.TcpClient){
for{
recv := make([]byte, 1024)
for {
n, err := conn.Connection.Read(recv)
if err != nil{
if err == io.EOF {
log.Println(conn.Addr(), " 断开了连接!")
conn.Close()
return
}
}
if n > 0 && n < 1025 {
conn.CmdChan <- entity.TransfeDataDecoder(recv[:n])
}
}
}
}(client)
// 发送心跳
go func(conn *models.TcpClient){
i := 0
heartBeatTick := time.Tick(10 * time.Second)
for {
select {
case <-heartBeatTick:
heartBeat := entity.NewTransfeData(enum.HeartPacket, "", i)
if _, err := conn.Send(heartBeat); err != nil {
models.RConn <- true
return
}
i++
case <-conn.StopChan:
return
}
}
}(client)
// 接收来自Server端的数据
go func(conn *TcpClient){
for{
select{
case data := <- c.CmdChan:
log.Println(data)
}
}
}(conn)
// 处理重连信号
for {
select {
case a := <- models.RConn:
log.Println("global.RConn = ", a)
goto Reconnection
}
}
//等待退出
<-client.StopChan
}
上一篇 1.选型与结构定义
https://blog.csdn.net/Man_ge/article/details/120204207
|