- TCP_NODELAY
1.TCP_NODELAY 和 NAGLE 算法
- 当我们通过 TCP socket 分多次发送较少的数据时,比如小于 1460 或者 100 以内,对端可能会很长时间收不到数据,导致本端应用程序认为超时报错。这时可能是受到了 TCP NAGLE 算法的影响。
2.NAGLE算法了解
3.一般双方建立连接后,便会做如下配置,经如下设置后,发送小数据可能会快一些
ns,addr = self.sock.accept()
print 'connect by', addr
ns.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
ns.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
ns.setblocking(False)
- SO_REUSEADDR
一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用。
SO_REUSEADDR用于对TCP套接字处于TIME_WAIT状态下的socket,才可以重复绑定使用。server程序总是应该在调用bind()之前设置SO_REUSEADDR套接字选项。TCP,先调用close()的一方会进入TIME_WAIT状态
示例:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.setblocking(False)
self.sock.bind((ip, port))
self.sock.listen(5)
-
signal(SIGCHLD, SIG_IGN);
因为并发服务器常常fork很多子进程,子进程终结之后需要服务器进程去wait清理资源。如果将此信号的处理方式设为忽略,可让内核把僵尸子进程转交给init进程去处理,省去了大量僵尸进程占用系统资源。(Linux Only)
对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下可以简单地将 SIGCHLD信号的操作设为SIG_IGN。
-
signal(SIGPIPE, SIG_IGN);
TCP是全双工的信道, 可以看作两条单工信道, TCP连接两端的两个端点各负责一条. 当对端调用close时, 虽然本意是关闭整个两条信道,但本端只是收到FIN包. 按照TCP协议的语义, 表示对端只是关闭了其所负责的那一条单工信道, 仍然可以继续接收数据. 也就是说, 因为TCP协议的限制,一个端点无法获知对端的socket是调用了close还是shutdown.
对一个已经收到FIN包的socket调用read方法, 如果接收缓冲已空, 则返回0, 这就是常说的表示连接关闭. 这里是引用
但第一次对其调用write方法时, 如果发送缓冲没问题, 会返回正确写入(发送).
但发送的报文会导致对端发送RST报文, 因为对端的socket已经调用了close, 完全关闭, 既不发送, 也不接收数据. 所以,第二次调用write方法(假设在收到RST之后), 会生成SIGPIPE信号, 导致进程退出.
为了避免进程退出, 可以捕获SIGPIPE信号, 或者忽略它, 给它设置SIG_IGN信号处理函数: signal(SIGPIPE, SIG_IGN);这样, 第二次调用write方法时, 会返回-1, 同时errno置为SIGPIPE. 程序便能知道对端已经关闭.
ErrorNo 9:
Udp sendto失败 errno 9 (EBADF Bad file descriptor)
在调试udp socket时遇到用sendto发送数据时报错出现 Bad file descriptor。
1、在进行sendto时 udp的socket已经关闭,大家可以自己写示例程序,建立一个udp socket 然后关闭这个socket,再用sendto进行发送,查看结果。这个问题同样适用tcp
2、多线程同时向同一个socket进行sendto数据,这个情况也可以自己写程序验证。(这种说法为网上查阅资料时看到的一种说法,但是自己写测试程序并没有试验出来,如果真实程序遇到这种情况在进行补充,测试程序也很简单就是不停的穿件线程,每个线程都想同一个socket中写数据。)