文章来源:https://blog.csdn.net/zhangjiehuan/article/details/93364890
如题,服务端调用listen处于监听状态,假如其不调用accept函数,客户端的connect函数能否调用成功?
我们做个试验试试:
1//服务端server.c
2#include <sys/types.h>
3#include <sys/socket.h>
4#include <stdio.h>
5#include <netinet/in.h>
6#include <arpa/inet.h>
7#include <unistd.h>
8#include <string.h>
9#include <stdlib.h>
10#include <fcntl.h>
11#include <sys/shm.h>
12#include <assert.h>
13
14int main()
15{
16 int serverfd = socket( PF_INET, SOCK_STREAM, 0 );
17 assert( serverfd >= 0 );
18
19 struct sockaddr_in address;
20 bzero( &address, sizeof( address ) );
21 address.sin_family = AF_INET;
22 address.sin_addr.s_addr = htonl(INADDR_ANY);
23 address.sin_port = htons( 54321 );
24
25 int ret = bind( serverfd, ( struct sockaddr* )&address, sizeof( address ) );
26 assert( ret != -1 );
27
28 ret = listen( serverfd, 5 );
29 assert( ret != -1 );
30
31 printf("server listen on 54321\n");
32
33 while(1)
34 {
35 sleep(5);
36 }
37 close(serverfd);
38
39 return 0;
40}
上面是服务端代码,然后我在windows下使用telnet命令模拟客户端(telnet不仅可以实现远程登录,还可以探测服务端开放了哪些端口,不知道的童鞋,去问问度娘吧~)
1[root@promote ~]# gcc server.c -o server
2[root@promote ~]# ./server
3server listen on 54321
我们先使用netstat命令查看其状态,如下
1[root@localhost ~]# netstat -at | grep 54321
2tcp 0 0 0.0.0.0:54321 0.0.0.0:* LISTEN
然后我们使用telnet命令连接,看能否建立连接
我们再使用netstat查看服务端状态
1[root@localhost ~]# netstat -at | grep 54321
2tcp 1 0 0.0.0.0:54321 0.0.0.0:* LISTEN
3tcp 2 0 promote.cache-dns:54321 promote.cache-dns:60530 ESTABLISHED
实验结果表明:服务端即使不调用accept,客户端依然可以connect成功。
这是什么原因呢?我们先上张图,如下:
当客户端调用connect函数时,将引发三次握手过程,如上图所示,客户端首先发送SYN请求分组,此时服务端会将请求放入SYN队列,同时向客户端发送ACK确认报文,然后客户端向服务端再次发送ACK报文。服务端收到ACK确认报文后,将SYN里的连接请求移入ACCEPT队列。此时三次握手结束,即TCP连接成功建立。然后内核通知用户空间的阻塞的服务进程,服务进程调用accept仅仅是从ACCEPT队列里取出一个连接而已。也就是说客户端调用connect连接服务器,与服务器调用accept“接受”连接是两个独立的过程。
上图中SYN队列和ACCEPT队列分别称为半连接队列与全连接队列。还记得listen函数怎么调用的吗?其原型如下:
1#include <sys/socket.h>
2
3int listen(int s, int backlog);
第二个参数backlog是什么意思?对,它就是全连接队列的长度。那么它有长度限制吗?当然有了,使用如下命令即可查看其最大值。
1[root@promote ~]# cat /proc/sys/net/core/somaxconn
2128
3[root@promote ~]#
也就是listen函数的第二个参数的最大不会超过128,即
1len = min (backlog,/proc/sys/net/core/somaxconn)
上面刚才说了,还有个半连接队列,那它的最大值是多少呢?其实它的取值遵循如下规则:
1syn_len = min (backlog, /proc/sys/net/core/somaxconn, /proc/sys/net/ipv4/tcp_max_syn_backlog)
好了,现在大家对题目提出的问题,应该清楚了吧,欢迎关注公众号,深入交流~