Skip to main content
Version: 2.8.x(Latest)

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)
  1. 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;
  2. 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.

tip

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.

tip

In practical scenarios, developers often need to customize package parsing protocols or adopt more general protobuf binary package encapsulation/parsing protocols.

  1. 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)
}
  1. 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()
}
  1. 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))
}
}
  1. 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