Socket之bind、listen实现
发布时间:2025-05-25 03:34:55 发布人:远客网络
一、Socket之bind、listen实现
1、 bind()函数的使用方法很简单,但是它是怎么实现的呢?
2、本文将从应用层出发,沿着网络协议栈,分析了bind()、 listen()的系统调用、Socket层实现,以及它的TCP层实现。
3、 int bind(int sockfd, const struct sockaddr*my_addr, socklen_t addrlen);
4、 bind() gives the socket sockfd the local address my_addr.
5、给socket描述符绑定IP和端口,一般服务器才需要。端口号的范围为0~ 65535。调用bind()时,一般不要把端口号置为小于1024的值,因为1到1023是保留端口号。
6、 bind()是由glibc提供的,声明位于include/sys/socket.h中,实现位于sysdeps/mach/hurd/bind.c中,主要是用来从用户空间进入名为sys_socketcall的系统调用,并传递参数。sys_scoketcall()实际上是所有socket函数进入内核空间的共同入口。
7、在sys_socketcall()中会调用sys_bind()。
8、经过了socket层的总入口sys_socketcall(),现在进入sys_bind()。
9、经过了socket层的总入口sys_socketcall(),现在进入sys_bind()。
10、通过文件描述符,找到对应的file结构。
11、通过file结构,找到对应的socket结构。
12、把用户空间的socket地址复制到内核空间,同时检查是否合法,成功返回0。
13、 SOCK_STREAM套接口的socket层操作函数集实例为inet_stream_ops,其中绑定函数为inet_bind()。
14、 socket层做的主要事情为合法性检查、绑定IP地址,而真正的端口绑定是在TCP层进行的。
15、 int listen(int sockfd, int backlog);
16、 Accept incoming connections and a queue limit for incoming connections.
17、 Now it specifies the queue length for completely established sockets waiting to be accepted,
18、 instead of the number of incomplete connection requests. The maximum length of the queue
19、 for incomplete sockets can be set using the tcp_max_syn_backlog sysctl. When syncookies
20、 are enabled there is no logical maximum length and this sysctl setting is ignored.
21、 backlog保存的是完成三次握手、等待accept的全连接,而不是半连接。
22、负载不高时,backlog不用太大。(For complete connections)
23、系统最大的、未处理的全连接数量为:min(backlog, somaxconn),net.core.somaxconn默认为128。
24、 tcp_max_syn_backlog默认值为256。(For incomplete connections)
25、当使用SYN Cookie时,这个参数变为无效。
26、半连接队列的最大长度为backlog、somaxconn、tcp_max_syn_backlog的最小值。
27、 listen()是由glibc提供的,声明位于include/sys/socket.h中,实现位于sysdeps/mach/hurd/listen.c中,主要是用来从用户空间进入名为sys_socketcall的系统调用,并传递参数。sys_socketcall()实际上是所有socket函数进入内核空间的共同入口。
28、在sys_socketcall()中会调用sys_listen()。
29、经过了socket层的总入口sys_socketcall(),现在进入sys_listen()。
30、 SOCK_STREAM套接口的socket层操作函数集实例为inet_stream_ops,其中监听函数为inet_listen()。
31、检查套接口的状态、当前连接的状态是否合法,然后调用inet_csk_listen_start()启动监听。
32、启动监听时,做的工作主要包括:
33、 listen_sock结构用于保存SYN_RECV状态的连接请求块,所以也叫半连接队列。
34、 queue是连接请求控制块,nr_table_entries是半连接的最大个数,即backlog。
35、销毁连接请求块中的listen_sock实例,释放半连接队列。
二、Linux socket的基本操作socket、bind、listen、accept
Linux socket的基本操作涉及到 socket、bind、listen、accept等关键函数。在开始之前,应明确 socket函数的作用类似于普通文件的打开操作,返回一个用于后续读写操作的描述符。创建 socket时,可通过指定参数类型和协议创建不同类型的 socket,但需注意不同类型和协议的组合限制。默认情况下,创建的 socket是主动类型的,后续应通过 bind函数为其绑定特定的地址和端口。bind函数接收地址族、地址和端口作为参数,用于将地址信息赋给 socket。服务器通常在启动时使用 bind函数绑定一个众所周知的地址,以便客户端能连接。而客户端则无需指定地址,系统会自动为其分配端口。在进行 socket操作时,需将主机字节序转换为网络字节序,以确保数据传输的一致性。服务器在调用 listen函数后变为被动监听状态,等待客户端连接请求。客户端调用 connect函数尝试建立连接,服务器通过 accept函数接收请求并建立连接。之后,即可进行网络 I/O操作,类似于普通文件的读写。读写操作可使用 recvmsg()/sendmsg()函数,它们是最通用的 I/O函数,能替代其他 I/O函数。完成操作后,通过 close函数关闭 socket描述符。close操作仅标记 socket为关闭状态,实际关闭需等待引用计数降至零。
三、bind函数的用法和参数
在网络编程中,bind函数起着至关重要的作用,它用于将套接字与特定的网络位置紧密连接。让我们深入了解其用法和参数:
int bind(SOCKET s, const struct sockaddr*addr, int namelen);
其中,第一个参数是待绑定的套接字,第二个参数是一个结构体,包含了要绑定的网络位置的信息,如协议、IP地址和端口号。第三个参数是这个位置信息的大小。
函数返回0表示绑定成功,-1则表示失败。在调用时,务必注意检查返回值,因为它能提供关于操作是否顺利的重要信息,比如下面的示例:
int iRet= bind(sockSrv,(SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
与文件I/O不同,网络I/O需要经过三个步骤来实现数据交互:
1.首先,创建或打开socket,为数据传输建立通道。
2.然后,通过bind函数对socket进行命名,它将socket与特定的网络地址和端口号关联起来,确保数据传输的正确目的地。
理解并正确使用bind函数是网络编程中必不可少的步骤,它确保了套接字与网络位置的一一对应,为数据传输提供了清晰的标识。务必在实际操作中熟练掌握其用法。