Socket之bind、listen实现
bind()函数的使用方法很简单,但是它是怎么实现的呢?
本文将从应用层出发,沿着网络协议栈,分析了bind()、 listen()的系统调用、Socket层实现,以及它的TCP层实现。
应用层
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
bind() gives the socket sockfd the local address my_addr.
给socket描述符绑定IP和端口,一般服务器才需要。端口号的范围为0 ~ 65535。调用bind()时,一般不要把端口号置为小于1024的值,因为1到1023是保留端口号。
系统调用
bind()是由glibc提供的,声明位于include/sys/socket.h中,实现位于sysdeps/mach/hurd/bind.c中,主要是用来从用户空间进入名为sys_socketcall的系统调用,并传递参数。sys_scoketcall()实际上是所有socket函数进入内核空间的共同入口。
在sys_socketcall()中会调用sys_bind()。
经过了socket层的总入口sys_socketcall(),现在进入sys_bind()。
经过了socket层的总入口sys_socketcall(),现在进入sys_bind()。
通过文件描述符,找到对应的file结构。
通过file结构,找到对应的socket结构。
把用户空间的socket地址复制到内核空间,同时检查是否合法,成功返回0。
socket层
SOCK_STREAM套接口的socket层操作函数集实例为inet_stream_ops,其中绑定函数为inet_bind()。
socket层做的主要事情为合法性检查、绑定IP地址,而真正的端口绑定是在TCP层进行的。
应用层
int listen(int sockfd, int backlog);
Accept incoming connections and a queue limit for incoming connections.
backlog的定义
Now it specifies the queue length for completely established sockets waiting to be accepted,
instead of the number of incomplete connection requests. The maximum length of the queue
for incomplete sockets can be set using the tcp_max_syn_backlog sysctl. When syncookies
are enabled there is no logical maximum length and this sysctl setting is ignored.
全连接队列的最大长度:
backlog保存的是完成三次握手、等待accept的全连接,而不是半连接。
负载不高时,backlog不用太大。(For complete connections)
系统最大的、未处理的全连接数量为:min(backlog, somaxconn),net.core.somaxconn默认为128。
半连接队列的最大长度:
tcp_max_syn_backlog默认值为256。(For incomplete connections)
当使用SYN Cookie时,这个参数变为无效。
半连接队列的最大长度为backlog、somaxconn、tcp_max_syn_backlog的最小值。
listen()是由glibc提供的,声明位于include/sys/socket.h中,实现位于sysdeps/mach/hurd/listen.c中,主要是用来从用户空间进入名为sys_socketcall的系统调用,并传递参数。sys_socketcall()实际上是所有socket函数进入内核空间的共同入口。
在sys_socketcall()中会调用sys_listen()。
经过了socket层的总入口sys_socketcall(),现在进入sys_listen()。
SOCK_STREAM套接口的socket层操作函数集实例为inet_stream_ops,其中监听函数为inet_listen()。
检查套接口的状态、当前连接的状态是否合法,然后调用inet_csk_listen_start()启动监听。
启动监听时,做的工作主要包括:
listen_sock结构用于保存SYN_RECV状态的连接请求块,所以也叫半连接队列。
(1)创建
queue是连接请求控制块,nr_table_entries是半连接的最大个数,即backlog。
(2)销毁
销毁连接请求块中的listen_sock实例,释放半连接队列。