当前位置: 首页 > article >正文

网络I/O学习(一)

一、什么是网络IO?

就是客户端和服务端之间的进行通信的通道(fd)。

二、网络IO通信步骤

1、建立套接字

int socketfd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //绑定0.0.0.0,Linux上有三张网卡,eth0:桥接,eth1:NAT,lo:回环,// 0.0.0.0代表任意一个收到数据都行,也可以绑定固定网卡上的ip地址
servaddr.sin_port = htons(2000);              // 0~1023:系统使用,1024以后用户可以使用
if (-1 == bind(socketfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)))
{cout << "bind failed:" << strerror(errno) << endl;
}

2、实现监听

listen(socketfd, 10); //监听struct sockaddr_in clientaddr; //创建一个客户端用于接受数据
socklen_t len = sizeof(clientaddr);
cout<<"current socketfd:"<<socketfd<<endl;
int clientfd = accept(socketfd, (struct sockaddr*)&clientaddr, &len);
cout<<"clientfd is:"<<clientfd<<endl;
netstat -anop | grep 2000		#新建一个窗口,输入该命令查看绑定的2000端口状态,  22查ssh,3306查mysql,6309查redis

在这里插入图片描述

如果再开一个窗口执行监听,那么会报错
在这里插入图片描述

3、接受数据 fd与tcp连接,io通道建立成功

会一直阻塞等待数据的到来

char buffer[1024] = {0};
int count = recv(clientfd, buffer, 1024, 0);
cout<<"buffer:"<<buffer<<endl;

4、返回信息

count = send(clientfd, buffer,count, 0);

5、由于代码中只存在两个fd,socketfd和clientfd

当存在一个客户端连接服务端时,可以正常收发消息;但当出现多个客户端连接服务端时,只有一个客户端能发信息,其余
客户端不能发送信息
在这里插入图片描述

在这里插入图片描述

客户端发送消息结果:
在这里插入图片描述

在这里插入图片描述

小结:

虽然3个客户端都连接服务端成功,但最终通信成功的只有一个,acept就调用成功一次就结束了,自然就接收不到其余两个客户端的数据

优化代码:

在这里插入图片描述

while (true){cout<<"current socketfd:"<<socketfd<<endl;int clientfd = accept(socketfd, (struct sockaddr *)&clientaddr, &len);cout<<"clientfd is:"<<clientfd<<endl;char buffer[1024] = {0};int count = recv(clientfd, buffer, 1024, 0);cout << "buffer:" << buffer << endl;//返回信息count = send(clientfd, buffer, count, 0);}

小结:

虽然都通信成功,但只能发送一次消息,无法发送第二次消息,在acept这进行了阻塞,而且必须根据连接顺序来处理信息,
比如连接顺序是1号,2号,3号客户端,3号连发3次消息,2号连发2次消息,此时服务端仍然没反应,在等待1号发消息,
1号发消息,然后服务端依次处理,将2号的2次消息,3号的3次消息全部发出,然后阻塞,需要有新的连接,然后才能处理消息。

存在两个问题:

1、无法实时响应。
2、一次性连接处理信息问题

三、多个IO如何接收数据

1、解决实时性问题和一次性连接处理问题

当多个客户端连接服务器时,accept会进行阻塞,等待第一个用户数据接收完之后,才处理第二个用户的请求…

解决方案:

采用多线程来解决。

void *ClientPthread(void *arg)
{int clientfd = *(int *)arg;while(true){cout<<"clientfd is:"<<clientfd<<endl;char buffer[1024] = {0};int count = recv(clientfd, buffer, 1024, 0);cout << "buffer:" << buffer << endl;//返回信息count = send(clientfd, buffer, count, 0);}
}while (true){cout<<"current socketfd:"<<socketfd<<endl;int clientfd = accept(socketfd, (struct sockaddr *)&clientaddr, &len);pthread_t p_id;pthread_create(&p_id, NULL, ClientPthread, &clientfd);}

在这里插入图片描述

2、讨论fd的值

无论什么时候连接,或者多个客户端连接,发现socketfd的值永远是3,而接收客户端返回的fd却是在3的基础上+1
那么fd,0,1,2去哪了

ls /dev/fd

在这里插入图片描述
在这里插入图片描述

原来这三个值分别是代表标准输入,输出以及错误
那允许多少客户端连接呢,fd是个整数,肯定也存在一定的范围

ulimit -a

在这里插入图片描述

当前最多只支持到这么多

3、fd支持有限,那客户端断开连接后,原来的fd还能用吗?

答案是肯定的,系统有自己的回收策略

int count = recv(clientfd, buffer, 1024, 0);if(count == 0){                  //断开close(clientfd);            //必须要有close,不然系统不会回收fd资源break;}

在这里插入图片描述

http://www.lryc.cn/news/2379325.html

相关文章:

  • 4:OpenCV—保存图像
  • Selenium-Java版(css表达式)
  • 产品更新丨谷云科技 iPaaS 集成平台 V7.5 版本发布
  • 深度学习让鱼与熊掌兼得
  • TDuckX 2.6 正式发布|API 能力开放,核心表单逻辑重构,多项实用功能上线。
  • LeetCode Hot100刷题——除自身以外数组的乘积
  • JAVA EE(进阶)_进阶的开端
  • PDF批量合并拆分+加水印转换 编辑 加密 OCR 识别
  • Go语言交替打印问题及多种实现方法
  • ArcGIS Pro调用多期历史影像
  • 10.11 LangGraph多角色Agent开发实战:生产级AI系统架构与性能优化全解析
  • 组态王|组态王中如何添加西门子1200设备
  • 发布时将多个bpl 打包成一个bpl的方法,或者说:不需要vcl60.bpl情况下 18.5K的exe 照常可以运行。
  • 6.2.2邻接表法-图的存储
  • C++23 放宽范围适配器以允许仅移动类型(P2494R2)
  • 【技海登峰】Kafka漫谈系列(十一)SpringBoot整合Kafka之消费者Consumer
  • Spring Boot三层架构设计模式
  • 在Java中调用Ant命令
  • WebRTC技术下的EasyRTC音视频实时通话SDK,助力车载通信打造安全高效的智能出行体验
  • 数据科学和机器学习的“看家兵器”——pandas模块 之二
  • 本地部署Firecrawl+Dify调用踩坑记录
  • MySQL--day2--基本的select语句
  • 什么是dom?作用是什么
  • Trae - 国人Cursor的免费平替产品
  • 自动化:批量文件重命名
  • Jsoup库和Apache HttpClient库有什么区别?
  • 学习!FastAPI
  • Linux 安装 Unreal Engine
  • 【第三十六周】LoRA 微调方法
  • 什么是 Boosting