
文中转载自微信公众号「盼盼编程」,作者盼盼编程。转截文中请联络盼盼编程微信公众号。
socket用listen函数监听,listen从英文上解释便是一个"听"函数公式,事实上它也就是这个意思。
大家看来unix网络编程这本书是如何对它的表述:listen函数把一个未联接的tcp协议转化成一个处于被动tcp协议,标示核心应当接纳偏向该tcp协议的连接要求。
该函数公式有2个主要参数,第一个我不讲了,第二主要参数要求了核心为相对应tcp协议排长队的最高联接数量。只看这种基础理论搞的人糊里糊涂,大家或是来测一下。
[mapan@localhosttest]$lsclient.cppmakefileserver.cpp[mapan@localhosttest]$[mapan@localhosttest]$catserver.cpp#include<unistd.h>#include<sys/types.h>#include<sys/socket.h>#include<netdb.h>#include<stdio.h>#include<stdlib.h>#include<string.h>#include<ctype.h>#include<errno.h>#include<malloc.h>#include<netinet/in.h>#include<arpa/inet.h>#include<sys/ioctl.h>#include<stdarg.h>#include<fcntl.h>#include<sys/types.h>#include<sys/wait.h>#include<netinet/in.h>#include<arpa/inet.h>#include<signal.h>#defineMAXLINE4096voidmain(){intlistenfd,connfd;socklen_tclilen;structsockaddr_incliaddr,servaddr;listenfd=socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof(servaddr));servaddr.sin_family=AF_INET;servaddr.sin_addr.s_addr=INADDR_ANY;servaddr.sin_port=htons(8888);bind(listenfd,(structsockaddr*)&servaddr,sizeof(servaddr));listen(listenfd,1);getchar();connfd=accept(listenfd,(structsockaddr*)&cliaddr,&clilen);close(connfd);close(listenfd);}[mapan@localhosttest]$catclient.cpp#include<unistd.h>#include<sys/types.h>#include<sys/socket.h>#include<netdb.h>#include<stdio.h>#include<stdlib.h>#include<string.h>#include<ctype.h>#include<errno.h>#include<malloc.h>#include<netinet/in.h>#include<arpa/inet.h>#include<sys/ioctl.h>#include<stdarg.h>#include<fcntl.h>#include<sys/types.h>#include<sys/wait.h>#include<netinet/in.h>#include<arpa/inet.h>#include<signal.h>#defineMAXLINE4096voidmain(){intsockfd;structsockaddr_inservaddr;sockfd=socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof(servaddr));servaddr.sin_family=AF_INET;servaddr.sin_port=htons(8888);servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");intret=connect(sockfd,(structsockaddr*)&servaddr,sizeof(servaddr));getchar();close(sockfd);}[mapan@localhosttest]$catmakefileall:serverclientserver.o:server.cppg -cserver.cppclient.o:client.cppg -cclient.cppserver:server.og -oserverserver.oclient:client.og -oclientclient.oclean:rm-fserverclient*.o[mapan@localhosttest]$
一定要注意上边的服务器端中,我是沒有启用accept函数公式的,立即启用getchar()了,跑起来。
[mapan@localhosttest]$makeg -cserver.cppg -oserverserver.og -cclient.cppg -oclientclient.o[mapan@localhosttest]$./server服务项目度打开,随后新开启一个对话框打开手机客户端。[mapan@localhostTCP]$cd../test/[mapan@localhosttest]$[mapan@localhosttest]$./client127.0.0.1
查询互联网:
[mapan@localhosttest]$netstat-na|grep8888tcp000.0.0.0:88880.0.0.0:*LISTENtcp00127.0.0.1:34846127.0.0.1:8888ESTABLISHEDtcp00127.0.0.1:8888127.0.0.1:34846ESTABLISHED[mapan@localhosttest]$
看,早已创建起一个联接了。可是大家沒有启用accept函数公式,联接或是创建起来了,这说表明accept函数公式和TCP三次握手没啥关联,这也是一个专业知识盲区。好,在开始一个新页面运作手机客户端,查询网络状态。(新开窗口运作手机客户端跟上面一样,这儿就无需编码演试了)
[mapan@localhosttest]$netstat-na|grep8888tcp000.0.0.0:88880.0.0.0:*LISTENtcp00127.0.0.1:34846127.0.0.1:8888ESTABLISHEDtcp00127.0.0.1:34848127.0.0.1:8888ESTABLISHEDtcp00127.0.0.1:8888127.0.0.1:34846ESTABLISHEDtcp00127.0.0.1:8888127.0.0.1:34848ESTABLISHED
看,又创建起一个联接。在运作一个手机客户端,看网络状态。
[mapan@localhosttest]$netstat-na|grep8888tcp000.0.0.0:88880.0.0.0:*LISTENtcp00127.0.0.1:8888127.0.0.1:34850SYN_RECVtcp00127.0.0.1:34846127.0.0.1:8888ESTABLISHEDtcp00127.0.0.1:34848127.0.0.1:8888ESTABLISHEDtcp00127.0.0.1:8888127.0.0.1:34846ESTABLISHEDtcp00127.0.0.1:8888127.0.0.1:34848ESTABLISHEDtcp00127.0.0.1:34850127.0.0.1:8888ESTABLISHED
当第三个客户端联接进去的情况下,发生了一个SYN_RECV,这标出第三个手机客户端沒有与服务器端创建联接。
大家listen函数设定的监视队列入1,那麼监视序列塞了2个以后就沒有往里塞了。这下大约明白了listen函数第二个主要参数的实际意义了吧,当主要参数为1的过程中只有监视2个tcp协议,这应当是以0逐渐数的。
为什么是大约呢?实际上unix网络程序编写上是那样说的:listen函数的第二个主要参数是ESTABLISHED和SYN_RECV之和,仅仅在监视序列沒有满的情形下,SYN_RECV情况不易再现。此刻在服务项目度键入一个字符会有啥成效呢?
回答对你说,就是那个SYN_RECV情况变为ESTABLISHED了,这也是 accept函数公式的功效。accept函数公式会将已经完成联接序列中的死对头项回到给过程,因此SYN_RECV变为ESTABLISHED了。这一状况交给我们去实践活动一下吧,仅有自身实践活动出的物品才算是自身的。