golang的读取tcp 连接上的数据包

855 阅读3分钟

io包:studygolang.com/pkgdoc
bufio包:studygolang.com/pkgdoc
net包:studygolang.com/pkgdoc

Dial函数和服务端建立连接:

conn, err := net.Dial("tcp", "google.com:80")
if err != nil {
	// handle error
}
fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
status, err := bufio.NewReader(conn).ReadString('\n')
// ...

Listen和accept函数创建的服务端:

ln, err := net.Listen("tcp", ":8080")
if err != nil {
	// handle error
}
for {
	conn, err := ln.Accept()
	if err != nil {
		// handle error
		continue
	}
	go handleConnection(conn)
}

conn接口

type Conn interface {
    // Read从连接中读取数据
    // Read方法可能会在超过某个固定时间限制后超时返回错误,该错误的Timeout()方法返回真
    Read(b []byte) (n int, err error)
    // Write从连接中写入数据
    // Write方法可能会在超过某个固定时间限制后超时返回错误,该错误的Timeout()方法返回真
    Write(b []byte) (n int, err error)
    // Close方法关闭该连接
    // 并会导致任何阻塞中的Read或Write方法不再阻塞并返回错误
    Close() error
    // 返回本地网络地址
    LocalAddr() Addr
    // 返回远端网络地址
    RemoteAddr() Addr
    // 设定该连接的读写deadline,等价于同时调用SetReadDeadline和SetWriteDeadline
    // deadline是一个绝对时间,超过该时间后I/O操作就会直接因超时失败返回而不会阻塞
    // deadline对之后的所有I/O操作都起效,而不仅仅是下一次的读或写操作
    // 参数t为零值表示不设置期限
    SetDeadline(t time.Time) error
    // 设定该连接的读操作deadline,参数t为零值表示不设置期限
    SetReadDeadline(t time.Time) error
    // 设定该连接的写操作deadline,参数t为零值表示不设置期限
    // 即使写入超时,返回值n也可能>0,说明成功写入了部分数据
    SetWriteDeadline(t time.Time) error
}

linux缓冲区

Linux系统默认的读写缓冲区大小是由内核参数决定的,具体大小取决于系统的配置和硬件性能。一般情况下,Linux系统的读写缓冲区大小是比较合理的,可以满足大部分应用程序的需求。 在Linux系统中,可以通过/sys/devices/system/node/nodeX/meminfo文件查看当前系统的内存使用情况,其中包括了缓冲区和缓存的大小。另外,可以通过sysctl命令查看和修改内核参数,其中包括了读写缓冲区的大小。 例如,可以使用以下命令查看当前系统的读写缓冲区大小: sysctl net.core.rmem_default sysctl net.core.wmem_default sysctl net.core.rmem_max sysctl net.core.wmem_max 其中,rmem_default和wmem_default表示TCP连接的默认读写缓冲区大小,rmem_max和wmem_max表示TCP连接的最大读写缓冲区大小。默认情况下,Linux系统的TCP连接的默认读写缓冲区大小为87380字节,最大读写缓冲区大小为16777216字节。

设置系统缓冲区的大小:func (c *conn) SetReadBuffer(bytes int) error

// SetReadBuffer 设置操作系统上此connection的的接收缓冲区的大小,
// TCP请求接收缓冲区是用来存储接收到的TCP数据包的地方。它的作用是在TCP连接的数据传输过程中,
// 暂时存储接收到的数据,等待应用程序处理。当TCP数据包到达时,它们会被存储在接收缓冲区中,
// 直到应用程序准备好处理它们。这样可以确保数据的可靠传输,因为如果数据包到达速度过快,
// 应用程序可能无法及时处理所有数据,导致数据丢失。同时,接收缓冲区还可以帮助控制TCP连接的流量,
// 避免过多的数据包拥塞网络,影响网络性能。因此,TCP请求接收缓冲区在TCP连接中起着非常重要的作用。
func (c *conn) SetReadBuffer(bytes int) error {
   if !c.ok() {
      return syscall.EINVAL
   }
   if err := setReadBuffer(c.fd, bytes); err != nil {
      return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
   }
   return nil
}

func setReadBuffer(fd *netFD, bytes int) error {
   err := fd.pfd.SetsockoptInt(syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes)
   runtime.KeepAlive(fd)
   return wrapSyscallError("setsockopt", err)
}

从tcpConn上读取数据包

// Read implements the Conn Read method.
func (c *conn) Read(b []byte) (int, error) {
   if !c.ok() {
      return 0, syscall.EINVAL
   }
   n, err := c.fd.Read(b)
   if err != nil && err != io.EOF {
      err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
   }
   return n, err
}