gtcp
provides many convenient native methods for connecting and operating data. However, in most application scenarios, developers need to design their own data structures and perform packaging/unpacking. Since the TCP
message protocol does not have message boundary protection, sticky packets can easily occur in complex network communication environments. Therefore, gtcp
also provides a simple data protocol, making it easy for developers to interact with message packages without worrying about processing details, including packaging/unpacking, as all these complex logics have been handled by gtcp
.
Simple Protocol
The gtcp
module offers a simple, lightweight data interaction protocol with high efficiency. The protocol format is as follows:
Data Length (16bit) | Data Field (variable length)
- Data Length: Default is
16-bit
(2 bytes
), used to identify the data length of the message body in bytes, not including its own 2 bytes; - Data Field: Variable length. With data length, the maximum data length cannot exceed
0xFFFF = 65535 bytes = 64 KB
;
The simple protocol is implemented by gtcp
. If both the client's and server's developers use the gtcp
module for communication, then there is no need to worry about protocol implementation, and they can focus on implementing/enclosing the Data
field. If interfacing with other development languages is involved, it only requires implementation according to this protocol, as the simple protocol is very lightweight, leading to low interfacing costs.
The Data field can also be empty, meaning no length at all.
Operation Methods
https://pkg.go.dev/github.com/gogf/gf/v2/net/gtcp
type Conn
func (c *Conn) SendPkg(data []byte, option ...PkgOption) error
func (c *Conn) SendPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) error
func (c *Conn) SendRecvPkg(data []byte, option ...PkgOption) ([]byte, error)
func (c *Conn) SendRecvPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) ([]byte, error)
func (c *Conn) RecvPkg(option ...PkgOption) (result []byte, err error)
func (c *Conn) RecvPkgWithTimeout(timeout time.Duration, option ...PkgOption) ([]byte, error)
As seen, the message package methods are named by adding the Pkg
keyword to the original basic connection operation methods for easy distinction.
Among them, the PkgOption
data structure in the request parameter is as follows, used to define the message package receiving strategy:
// Data reading options
type PkgOption struct {
HeaderSize int // Custom header size (default is 2 bytes, maximum cannot exceed 4 bytes)
MaxDataSize int // (byte) Maximum package size for data reading, default maximum cannot exceed 2 bytes (65535 byte)
Retry Retry // Failure retry policy
}
Usage Examples
Example 1, Basic Usage
package main
import (
"fmt"
"github.com/gogf/gf/v2/net/gtcp"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/util/gconv"
"time"
)
func main() {
// Server
go gtcp.NewServer("127.0.0.1:8999", func(conn *gtcp.Conn) {
defer conn.Close()
for {
data, err := conn.RecvPkg()
if err != nil {
fmt.Println(err)
break
}
fmt.Println("receive:", data)
}
}).Run()
time.Sleep(time.Second)
// Client
conn, err := gtcp.NewConn("127.0.0.1:8999")
if err != nil {
panic(err)
}
defer conn.Close()
for i := 0; i < 10000; i++ {
if err := conn.SendPkg([]byte(gconv.String(i))); err != nil {
glog.Error(err)
}
time.Sleep(1*time.Second)
}
}
This example is quite simple. After execution, the output result is:
receive: [48]
receive: [49]
receive: [50]
receive: [51]
...
Example 2, Custom Data Structure
In most scenarios, we need to customize the data structure for the messages sent. Developers can use the Data
field to transmit any message content.
Below is a simple example of a custom data structure for a client to report the current memory and CPU usage of the host node. In this example, the Data
field uses JSON
data format for customization, making data encoding/decoding easier.
In practical scenarios, developers often need to customize package parsing protocols or adopt more general protobuf
binary package encapsulation/parsing protocols.
types/types.go
Data structure definition.
package types
import "github.com/gogf/gf/v2/frame/g"
type NodeInfo struct {
Cpu float32 // CPU percentage (%)
Host string // Host name
Ip g.Map // IP address information (possibly multiple)
MemUsed int // Memory used (byte)
MemTotal int // Total memory (byte)
Time int // Reporting time (timestamp)
}
gtcp_monitor_server.go
Server.
package main
import (
"encoding/json"
"github.com/gogf/gf/v2/net/gtcp"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/.example/net/gtcp/pkg_operations/monitor/types"
)
func main() {
// Server, receive client data and format it into a specified data structure, print
gtcp.NewServer("127.0.0.1:8999", func(conn *gtcp.Conn) {
defer conn.Close()
for {
data, err := conn.RecvPkg()
if err != nil {
if err.Error() == "EOF" {
glog.Println("client closed")
}
break
}
info := &types.NodeInfo{}
if err := json.Unmarshal(data, info); err != nil {
glog.Errorf("invalid package structure: %s", err.Error())
} else {
glog.Println(info)
conn.SendPkg([]byte("ok"))
}
}
}).Run()
}
gtcp_monitor_client.go
Client.
package main
import (
"encoding/json"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/gtcp"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/.example/net/gtcp/pkg_operations/monitor/types"
)
func main() {
// Data reporting client
conn, err := gtcp.NewConn("127.0.0.1:8999")
if err != nil {
panic(err)
}
defer conn.Close()
// Format data fields using JSON
info, err := json.Marshal(types.NodeInfo{
Cpu : float32(66.66),
Host : "localhost",
Ip : g.Map {
"etho" : "192.168.1.100",
"eth1" : "114.114.10.11",
},
MemUsed : 15560320,
MemTotal : 16333788,
Time : int(gtime.Timestamp()),
})
if err != nil {
panic(err)
}
// Use SendRecvPkg to send a message package and receive return
if result, err := conn.SendRecvPkg(info); err != nil {
if err.Error() == "EOF" {
glog.Println("server closed")
}
} else {
glog.Println(string(result))
}
}
-
After execution
-
The client output result is:
2019-05-03 13:33:25.710 ok
-
The server output result is:
2019-05-03 13:33:25.710 &{66.66 localhost map[eth1:114.114.10.11 etho:192.168.1.100] 15560320 16333788 1556861605}
2019-05-03 13:33:25.710 client closed
-