Go语言中TCP/IP网络编程的深入讲解

2020-01-28 13:01:56于丽

有两个可用选项可以微调。

因此Dialer接口提供了可以微调的两方面选项:

DeadLine和Timeout选项: 用于不成功拨号的超时设置。 KeepAlive选项: 管理连接的使用寿命(life span)。

type Conn interface {
 Read(b []byte) (n int, err error)
 Write(b []byte) (n int, err error)
 Close() error
 LocalAddr() Addr
 RemoteAddr() Addr
 SetDeadline(t time.Time) error
 SetReadDeadline(t time.Time) error
 SetWriteDeadline(t time.Time) error
}

net.Conn接口是面向流的一般的网络连接。它具有下面这些接口方法:

Read(): 从连接上读取数据。 Write(): 向连接上写入数据。 Close(): 关闭连接。 LocalAddr(): 返回本地网络地址。 RemoteAddr(): 返回远程网络地址。 SetDeadline(): 设置连接相关的读写最后期限。等价于同时调用SetReadDeadline()和SetWriteDeadline()。 SetReadDeadline(): 设置将来的读调用和当前阻塞的读调用的超时最后期限。 SetWriteDeadline(): 设置将来写调用以及当前阻塞的写调用的超时最后期限。

Conn接口也有deadline设置; 有对整个连接的(SetDeadLine()),也有特定读写调用的(SetReadDeadLine()和SetWriteDeadLine())。

注意deadline是(wallclock)时间固定点。和timeout不同,它们新活动之后不会重置。因此连接上的每个活动必须设置新的deadline。

下面的样本代码没有使用deadline, 因为它足够简单,我们可以很容易看到什么时候会被卡住。Ctrl-C时我们手动触发deadline的工具。

接收端上

接收端步骤如下:

对本地端口打开监听。 当请求到来时,产生(spawn)goroutine来处理请求。 在goroutine中,读取数据。也可以选择性的发送响应。 关闭连接。

监听需要指定本地监听的端口号。一般来说,监听应用程序(也叫server)宣布监听的端口号,如果提供标准服务, 那么使用这个服务对应的相关端口。例如,web服务通常监听80来伺服HTTP, 443端口伺服HTTPS请求。 SSH守护默认监听22端口, WHOIS服务使用端口43。


type Listener interface {
 // Accept waits for and returns the next connection to the listener.
 Accept() (Conn, error)

 // Close closes the listener.
 // Any blocked Accept operations will be unblocked and return errors.
 Close() error

 // Addr returns the listener's network address.
 Addr() Addr
}

func Listen(network, address string) (Listener, error) {
 addrs, err := DefaultResolver.resolveAddrList(context.Background(), "listen", network, address, nil)
 if err != nil {
 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: nil, Err: err}
 }
 var l Listener
 switch la := addrs.first(isIPv4).(type) {
 case *TCPAddr:
 l, err = ListenTCP(network, la)
 case *UnixAddr:
 l, err = ListenUnix(network, la)
 default:
 return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: address}}
 }
 if err != nil {
 return nil, err // l is non-nil interface containing nil pointer
 }
 return l, nil
}