当前位置: 首页 > 科技观察

窥探Socket监控的秘密

时间:2023-03-18 02:40:19 科技观察

本文转载自微信公众号《盼盼编程》,作者盼盼编程。转载本文请联系盼盼编程公众号。socket使用listen函数进行监听,listen在英文中理解为“监听”的功能,其实就是这个意思。看看Unix网络编程这本书是怎么解释的:listen函数将一个未连接的socket转换成被动socket,表示内核应该接受指向该socket的连接请求。这个函数有2个参数,第一个我就不说了,第二个参数指定内核为对应的socket排队的最大连接数。只看这些理论的人都一头雾水,我们来测试一下。[mapan@localhosttest]$lsclient.cppmakefileserver.cpp[mapan@localhosttest]$[mapan@localhosttest]$catserver.cpp#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#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);绑定(listenfd,(structsockaddr*)&servaddr,sizeof(servaddr));听(listenfd,1);getchar();connfd=accept(listenfd,(structsockaddr*)&cliaddr,&clien);关闭(connfd);关闭(listenfd);}[mapan@localhosttest]$catclient.cpp#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#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(),然后运行up[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三次握手无关,这也是一个知识盲点。OK,在新窗口运行客户端,查看网络状态。(新窗口运行客户端同上,这里不用代码演示)[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:34848建立了另一个连接。运行客户端以查看网络状态。[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个socket,应该是从0开始,为什么粗略呢?其实Unix网络编程是这样说的:监听函数的第二个参数是ESTABLISHED和SYN_RECV之和,但是监听队列未满时SYN_RECV状态不容易重现。这个时候在服务中输入一个字符会有什么效果呢?答案告诉你SYN_RECV状态变成了ESTABLISHED,这也是accept函数的作用。accept函数会将完成的连接队列中的对等项返回给进程,因此SYN_RECV变为ESTABLISHED。这个现象留给大家去实践。只有你练习的才是你自己的。