listen函数把一个由socket函数创建的套接字转换成一个被动套接字,指示内核接受指向该套接字的连接请求。该套接字也由CLOSED状态转换到LISTEN状态。
函数原型:
#include <sys/socket.h>
int listen(int sockfd, int backlog);
成功返回0,失败返回-1。
listen之后内核为给定的监听套接字维护两个队列:未完成连接队列,已完成连接队列。
未完成连接队列:已接受客户端的SYN分节,而且已经发送了第二个SYN分节和第一个SYN分节的ACK。
已完成连接队列:在未连接基础上接受到了客户端的ACK响应,TCP3路握手完成(此时accept并没有参与),
等待accept从该队列头返回。
backlog参数就是指已完成连接队列的个数,已完成连接队列的实际数目往往比backlog稍大;比如Linux是比backlog大3。如果不想让客户端连接到你的服务器上,千万不要把backlog指定为0,一定要把这个套接字关闭。
既然已完成连接队列的数目是有backlog指定的,那么未完成队列的数目又是多少?Berkeley给出了一个模 糊因子,backlog乘以1.5得到两个队列数目之和。假如backlog=10,那么未完成连接队列数目就是5。
当队列已满时,一个客户SYN到达时,服务器的TCP就忽略该分节(一般不向客户端发送RST),让对端 的TCP重传机制来处理。
如果有黑客编写了一个以高速率给受害主机发送SYN的程序,就会导致正常的客户SYN排不上队,这就是 SYN flooding攻击。主流的解决方法是从防火墙那里入手,确保到达服务器的TCP连接都是正常。