The gtcp module provides an easy-to-use gtcp.Conn link operation object.

Usage:

  1. import "github.com/gogf/gf/v2/net/gtcp"

API Documentation:

https://pkg.go.dev/github.com/gogf/gf/v2/net/gtcp

  1. type Conn
  2. func NewConn(addr string, timeout ...int) (*Conn, error)
  3. func NewConnByNetConn(conn net.Conn) *Conn
  4. func NewConnKeyCrt(addr, crtFile, keyFile string) (*Conn, error)
  5. func NewConnTLS(addr string, tlsConfig *tls.Config) (*Conn, error)
  6. func (c *Conn) Close() error
  7. func (c *Conn) LocalAddr() net.Addr
  8. func (c *Conn) Recv(length int, retry ...Retry) ([]byte, error)
  9. func (c *Conn) RecvLine(retry ...Retry) ([]byte, error)
  10. func (c *Conn) RecvWithTimeout(length int, timeout time.Duration, retry ...Retry) ([]byte, error)
  11. func (c *Conn) RemoteAddr() net.Addr
  12. func (c *Conn) Send(data []byte, retry ...Retry) error
  13. func (c *Conn) SendRecv(data []byte, receive int, retry ...Retry) ([]byte, error)
  14. func (c *Conn) SendRecvWithTimeout(data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error)
  15. func (c *Conn) SendWithTimeout(data []byte, timeout time.Duration, retry ...Retry) error
  16. func (c *Conn) SetDeadline(t time.Time) error
  17. func (c *Conn) SetRecvBufferWait(bufferWaitDuration time.Duration)
  18. func (c *Conn) SetRecvDeadline(t time.Time) error
  19. func (c *Conn) SetSendDeadline(t time.Time) error

Writing Operation

The TCP communication writing operation is implemented by the Send method, providing an error retry mechanism via the second optional parameter retry. Note that the Send method does not have any buffering mechanism, meaning that each call to the Send method will immediately invoke the underlying TCP Write method to write data (buffering relies on the system’s underlying implementation). Therefore, if you want to control output buffering, please handle it at the business layer.

When performing TCP writes, reliable communication scenarios often involve a write and a read, i.e., starting Recv to get the target’s feedback result immediately after a successful Send. Therefore, gtcp.Conn also offers a convenient SendRecv method.

Reading Operation

The TCP communication reading operation is implemented by the Recv method, which also provides an error retry mechanism via a second optional parameter retry. The Recv method offers built-in read buffer control, allowing you to specify the reading length (specified by the length parameter). It will immediately return when the specified length of data has been read. If length < 0, it will read all readable buffer data and return it. When length = 0, it means to get the buffered data once and return immediately.

Using Recv(-1) can read all readable buffer data (with indefinite length, possible truncation if the sent data packet is too long), but be cautious of packet parsing issues, which can easily result in incomplete packets. In this case, the business layer needs to ensure data packet integrity based on the predetermined protocol structure. It is recommended to use the simple protocol introduced later via SendPkg/ RecvPkg to send/receive message packets, as described in subsequent sections.

Timeout Handling

gtcp.Conn provides timeout handling for TCP communication data writing and reading, specified via the timeout parameter in the method, which is straightforward and won’t be elaborated further.


Next, we’ll look at how to use the gtcp.Conn object through some examples.

Usage Examples

Example 1, Simple Usage

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/gogf/gf/v2/net/gtcp"
  6. "github.com/gogf/gf/v2/os/glog"
  7. "github.com/gogf/gf/v2/util/gconv"
  8. )
  9. func main() {
  10. // Server
  11. go gtcp.NewServer("127.0.0.1:8999", func(conn *gtcp.Conn) {
  12. defer conn.Close()
  13. for {
  14. data, err := conn.Recv(-1)
  15. if len(data) > 0 {
  16. fmt.Println(string(data))
  17. }
  18. if err != nil {
  19. break
  20. }
  21. }
  22. }).Run()
  23. time.Sleep(time.Second)
  24. // Client
  25. conn, err := gtcp.NewConn("127.0.0.1:8999")
  26. if err != nil {
  27. panic(err)
  28. }
  29. for i := 0; i < 10000; i++ {
  30. if err := conn.Send([]byte(gconv.String(i))); err != nil {
  31. glog.Error(err)
  32. }
  33. time.Sleep(time.Second)
  34. }
  35. }
  1. On the Server side, received client data is immediately printed to the terminal.
  2. On the Client side, the same connection object is used to send an incrementing number to the server every second in a loop. This function also demonstrates that underlying Socket communication does not use buffering; executing a Send immediately sends data to the server. Therefore, the client needs to manage the buffered data to be sent locally.
  3. Execution result After execution, you can see the server outputting the following information on the terminal:
  1. 2018-07-11 22:11:08.650 0
  2. 2018-07-11 22:11:09.651 1
  3. 2018-07-11 22:11:10.651 2
  4. 2018-07-11 22:11:11.651 3
  5. 2018-07-11 22:11:12.651 4
  6. 2018-07-11 22:11:13.651 5
  7. 2018-07-11 22:11:14.652 6
  8. 2018-07-11 22:11:15.652 7
  9. 2018-07-11 22:11:16.652 8
  10. 2018-07-11 22:11:17.652 9
  11. 2018-07-11 22:11:18.652 10
  12. 2018-07-11 22:11:19.653 11
  13. ...

Example 2, Echo Service

Let’s improve the previous echo service:

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/gogf/gf/v2/net/gtcp"
  6. "github.com/gogf/gf/v2/os/glog"
  7. "github.com/gogf/gf/v2/os/gtime"
  8. )
  9. func main() {
  10. // Server
  11. go gtcp.NewServer("127.0.0.1:8999", func(conn *gtcp.Conn) {
  12. defer conn.Close()
  13. for {
  14. data, err := conn.Recv(-1)
  15. if len(data) > 0 {
  16. if err := conn.Send(append([]byte("> "), data...)); err != nil {
  17. fmt.Println(err)
  18. }
  19. }
  20. if err != nil {
  21. break
  22. }
  23. }
  24. }).Run()
  25. time.Sleep(time.Second)
  26. // Client
  27. for {
  28. if conn, err := gtcp.NewConn("127.0.0.1:8999"); err == nil {
  29. if b, err := conn.SendRecv([]byte(gtime.Datetime()), -1); err == nil {
  30. fmt.Println(string(b), conn.LocalAddr(), conn.RemoteAddr())
  31. } else {
  32. fmt.Println(err)
  33. }
  34. conn.Close()
  35. } else {
  36. glog.Error(err)
  37. }
  38. time.Sleep(time.Second)
  39. }
  40. }

In this example program, the Client sends the current time information to the Server every second, and the Server returns the original data message upon reception. Upon receiving the server-side return message, the Client immediately prints it to the terminal.

Execution results in output as follows:

  1. > 2018-07-19 23:25:43 127.0.0.1:34306 127.0.0.1:8999
  2. > 2018-07-19 23:25:44 127.0.0.1:34308 127.0.0.1:8999
  3. > 2018-07-19 23:25:45 127.0.0.1:34312 127.0.0.1:8999
  4. > 2018-07-19 23:25:46 127.0.0.1:34314 127.0.0.1:8999

Example 3, HTTP Client

In this example, we use the gtcp package to implement a simple HTTP client, reading and printing the header and content of the Baidu homepage.

  1. package main
  2. import (
  3. "fmt"
  4. "bytes"
  5. "github.com/gogf/gf/v2/net/gtcp"
  6. "github.com/gogf/gf/v2/util/gconv"
  7. )
  8. func main() {
  9. conn, err := gtcp.NewConn("www.baidu.com:80")
  10. if err != nil {
  11. panic(err)
  12. }
  13. defer conn.Close()
  14. if err := conn.Send([]byte("GET / HTTP/1.1\r\n\r\n")); err != nil {
  15. panic(err)
  16. }
  17. header := make([]byte, 0)
  18. content := make([]byte, 0)
  19. contentLength := 0
  20. for {
  21. data, err := conn.RecvLine()
  22. // Header reading, parsing text length
  23. if len(data) > 0 {
  24. array := bytes.Split(data, []byte(": "))
  25. // Get page content length
  26. if contentLength == 0 && len(array) == 2 && bytes.EqualFold([]byte("Content-Length"), array[0]) {
  27. contentLength = gconv.Int(string(array[1][:len(array[1])-1])) }
  28. header = append(header, data...)
  29. header = append(header, '\n')
  30. }
  31. // Header reading complete, read text content
  32. if contentLength > 0 && len(data) == 1 {
  33. content, _ = conn.Recv(contentLength)
  34. break
  35. }
  36. if err != nil {
  37. fmt.Errorf("ERROR: %s\n", err.Error())
  38. break
  39. }
  40. }
  41. if len(header) > 0 {
  42. fmt.Println(string(header))
  43. }
  44. if len(content) > 0 {
  45. fmt.Println(string(content))
  46. }
  47. }

Execution results in output as follows:

  1. HTTP/1.1 200 OK
  2. Accept-Ranges: bytes
  3. Cache-Control: no-cache
  4. Connection: Keep-Alive
  5. Content-Length: 14615
  6. Content-Type: text/html
  7. Date: Sat, 21 Jul 2018 04:21:03 GMT
  8. Etag: "5b3c3650-3917"
  9. Last-Modified: Wed, 04 Jul 2018 02:52:00 GMT
  10. P3p: CP=" OTI DSP COR IVA OUR IND COM "
  11. Pragma: no-cache
  12. Server: BWS/1.1
  13. ...
  14. (truncated)