SO_REUSEADDR

  允许 TCP server crash/kill 后复用端口,立即重启。

  传统的 fork-per-connection 模型需要使用,fork 出的子进程后,父进程的 listen 退出后,子进程也能立刻侦听该端口。

SIGPIPE

  向一个已关闭的 socket 或 pipe 写入数据,send() 会返回 -1,errno 为 EPIPE,同时系统会发出一个SIGPIPE信号给进程。

  收到 SIGPIPE 的默认行为是终止进程,对于命令行管道效果不错。例如以下命令,用来解压缩一个大的日志文件 “huge.log.gz”:

1
gunzip -c huge.log.gz | grep ERROR | head

  找出日志文件中含有 ERROR 的行,head 打印输出的前 10 行,之后就关闭,grep ERROR 则会收到 SIGPIPE 信号,gunzip 也会收到 SIGPIPE,避免将整个大文件解压缩。

  而在网络编程情况下,如果一个 client 关闭 socket,服务器如果不作处理,则会收到 SIGPIPE 而退出,并影响到其他所有 client。因此服务器进程启动时,应先将 SIGPIPE 信号忽略掉

Nagle 算法与 TCP_NODELAY

  TCP socket 默认情况下,发送数据使用Nagle算法。能够减少网络中小分组的数目,提高网络吞吐量,但降低了应用程序的实时性。

  如果存在任何一个未被 ACK 的分组,send()将不会发送后续数据。因此在 “write - write - read” 情况下,第二个 write 将延迟一个 RTT(往返时间),可以通过一个 buffer,将前两个 write 合并为一个 write 一起 send() 出去来解决。若要在同一个连接上发送并发请求,且这些并发请求可能位于程序的不同部分,无法合并为一个大请求,称为 “request pipelining”,这种情况依然会影响程序的延迟。

  因此建议设置TCP_NODELAY禁用 Nagle 算法,如 Go 语言对每个 TCP 连接默认禁用 Nagle 算法。