您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

窥探 socket 监听的秘密

时间:2021-08-13 11:49:28  来源:公众号  作者:盼盼编程

socket用listen函数监听,listen从英语上理解就是一个"听"函数,实际上它也就是这个意思。

我们来看unix网络编程这本书是怎样对它的解释:listen函数把一个未连接的套接字转换成一个被动套接字,指示内核应该接受指向该套接字的链接请求。

该函数有2个参数,第一个我就不说了,第二参数规定了内核为相应套接字排队的最大连接个数。只看这些理论搞的人稀里糊涂,我们还是来测一下。

[mapan@localhost test]$ ls
client.cpp  makefile  server.cpp
[mapan@localhost test]$ 
[mapan@localhost test]$ cat server.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>
#define MAXLINE 4096



void main()
{
   int listenfd,connfd;
   socklen_t  clilen;
   struct sockaddr_in cliaddr,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,(struct sockaddr *)&servaddr,sizeof(servaddr));  
   listen(listenfd,1);


   getchar();
   connfd=accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);



   close(connfd);
   close(listenfd);
}
[mapan@localhost test]$ cat client.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>
#define MAXLINE 4096




void main()
{
   int sockfd;
   struct sockaddr_in servaddr;




   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");


   int ret=connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
   getchar();


   close(sockfd);
}
[mapan@localhost test]$ cat makefile 
all:server client


server.o:server.cpp
  g++ -c server.cpp
client.o:client.cpp
  g++ -c client.cpp
server:server.o
  g++ -o server server.o
client:client.o
  g++ -o client client.o


clean:
  rm -f server client *.o
[mapan@localhost test]$

请注意上面的服务端中,我是没有调用accept函数的,直接调用getchar()了,跑起来。

[mapan@localhost test]$ make
g++ -c server.cpp
g++ -o server server.o
g++ -c client.cpp
g++ -o client client.o
[mapan@localhost test]$ ./server 


服务度开启,然后新打开一个窗口开启客户端。
[mapan@localhost TCP]$ cd ../test/
[mapan@localhost test]$ 
[mapan@localhost test]$ ./client 127.0.0.1

查看网络:

[mapan@localhost test]$ netstat -na | grep 8888
tcp        0      0 0.0.0.0:8888                0.0.0.0:*                   LISTEN      
tcp        0      0 127.0.0.1:34846             127.0.0.1:8888              ESTABLISHED 
tcp        0      0 127.0.0.1:8888              127.0.0.1:34846             ESTABLISHED 
[mapan@localhost test]$

看,已经建立起一个连接了。但是我们没有调用accept函数,连接还是建立起来了,这说说明accept函数和TCP三次握手没啥关系,这也是一个知识盲点。好,在开启一个新窗口运行客户端,查看网络状态。(新开窗口运行客户端同上,这里就不用代码演示了)

[mapan@localhost test]$ netstat -na | grep 8888
tcp        0      0 0.0.0.0:8888                0.0.0.0:*                   LISTEN      
tcp        0      0 127.0.0.1:34846             127.0.0.1:8888              ESTABLISHED 
tcp        0      0 127.0.0.1:34848             127.0.0.1:8888              ESTABLISHED 
tcp        0      0 127.0.0.1:8888              127.0.0.1:34846             ESTABLISHED 
tcp        0      0 127.0.0.1:8888              127.0.0.1:34848             ESTABLISHED

看,又建立起一个连接。在运行一个客户端,看网络状态。

[mapan@localhost test]$ netstat -na | grep 8888
tcp        0      0 0.0.0.0:8888                0.0.0.0:*                   LISTEN      
tcp        0      0 127.0.0.1:8888              127.0.0.1:34850             SYN_RECV    
tcp        0      0 127.0.0.1:34846             127.0.0.1:8888              ESTABLISHED 
tcp        0      0 127.0.0.1:34848             127.0.0.1:8888              ESTABLISHED 
tcp        0      0 127.0.0.1:8888              127.0.0.1:34846             ESTABLISHED 
tcp        0      0 127.0.0.1:8888              127.0.0.1:34848             ESTABLISHED 
tcp        0      0 127.0.0.1:34850             127.0.0.1:8888              ESTABLISHED

当第三个客户端连接进来的时候,出现了一个SYN_RECV,这标明第三个客户端没有与服务端建立连接。

我们listen函数设置的监听队列为1,那么监听队列塞了2个之后就没有往里面塞了。这下大概懂了listen函数第二个参数的意义了吧,当参数为1的时候只能监听2个套接字,这应该是从0开始数的。

为什么是大概呢?其实unix网络编程上是这样说的:listen函数的第二个参数是ESTABLISHED和SYN_RECV之和,只是在监听队列没有满的情况下,SYN_RECV状态不容易重现。这时候在服务度输入一个字符会有啥效果呢?

答案告诉你,就是那个SYN_RECV状态变成ESTABLISHED了,这也是 accept函数的作用。accept函数会将已完成连接队列中的对头项返回给进程,所以SYN_RECV变成ESTABLISHED了。这个现象留给大家去实践一下吧,只有自己实践出来的东西才是自己的。

 

原文出自:公众号 盼盼编程

原文链接:
https://mp.weixin.qq.com/s/zGzlpHavPdgSaMTu2Vs9tg



Tags:socket 监听   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
socket用listen函数监听,listen从英语上理解就是一个"听"函数,实际上它也就是这个意思。我们来看unix网络编程这本书是怎样对它的解释:listen函数把一个未连接的套接字转换成一...【详细内容】
2021-08-13  Tags: socket 监听  点击:(75)  评论:(0)  加入收藏
▌简易百科推荐
摘 要 (OF作品展示)OF之前介绍了用python实现数据可视化、数据分析及一些小项目,但基本都是后端的知识。想要做一个好看的可视化大屏,我们还要学一些前端的知识(vue),网上有很多比...【详细内容】
2021-12-27  项目与数据管理    Tags:Vue   点击:(1)  评论:(0)  加入收藏
程序是如何被执行的&emsp;&emsp;程序是如何被执行的?许多开发者可能也没法回答这个问题,大多数人更注重的是如何编写程序,却不会太注意编写好的程序是如何被运行,这并不是一个好...【详细内容】
2021-12-23  IT学习日记    Tags:程序   点击:(9)  评论:(0)  加入收藏
阅读收获✔️1. 了解单点登录实现原理✔️2. 掌握快速使用xxl-sso接入单点登录功能一、早期的多系统登录解决方案 单系统登录解决方案的核心是cookie,cookie携带会话id在浏览器...【详细内容】
2021-12-23  程序yuan    Tags:单点登录(   点击:(8)  评论:(0)  加入收藏
下载Eclipse RCP IDE如果你电脑上还没有安装Eclipse,那么请到这里下载对应版本的软件进行安装。具体的安装步骤就不在这赘述了。创建第一个标准Eclipse RCP应用(总共分为六步)1...【详细内容】
2021-12-22  阿福ChrisYuan    Tags:RCP应用   点击:(7)  评论:(0)  加入收藏
今天想简单聊一聊 Token 的 Value Capture,就是币的价值问题。首先说明啊,这个话题包含的内容非常之光,Token 的经济学设计也可以包含诸多问题,所以几乎不可能把这个问题说的清...【详细内容】
2021-12-21  唐少华TSH    Tags:Token   点击:(9)  评论:(0)  加入收藏
实现效果:假如有10条数据,分组展示,默认在当前页面展示4个,点击换一批,从第5个开始继续展示,到最后一组,再重新返回到第一组 data() { return { qList: [], //处理后...【详细内容】
2021-12-17  Mason程    Tags:VUE   点击:(14)  评论:(0)  加入收藏
什么是性能调优?(what) 为什么需要性能调优?(why) 什么时候需要性能调优?(when) 什么地方需要性能调优?(where) 什么时候来进行性能调优?(who) 怎么样进行性能调优?(How) 硬件配...【详细内容】
2021-12-16  软件测试小p    Tags:性能调优   点击:(19)  评论:(0)  加入收藏
Tasker 是一款适用于 Android 设备的高级自动化应用,它可以通过脚本让重复性的操作自动运行,提高效率。 不知道从哪里听说的抖音 app 会导致 OLED 屏幕烧屏。于是就现学现卖,自...【详细内容】
2021-12-15  ITBang    Tags:抖音防烧屏   点击:(23)  评论:(0)  加入收藏
11 月 23 日,Rust Moderation Team(审核团队)在 GitHub 上发布了辞职公告,即刻生效。根据公告,审核团队集体辞职是为了抗议 Rust 核心团队(Core team)在执行社区行为准则和标准上...【详细内容】
2021-12-15  InfoQ    Tags:Rust   点击:(24)  评论:(0)  加入收藏
一个项目的大部分API,测试用例在参数和参数值等信息会有很多相似的地方。我们可以复制API,复制用例来快速生成,然后做细微调整既可以满足我们的测试需求1.复制API:在菜单发布单...【详细内容】
2021-12-14  AutoMeter    Tags:AutoMeter   点击:(20)  评论:(0)  加入收藏
相关文章
    无相关信息
最新更新
栏目热门
栏目头条