linux网络编程 | c | select实现多路IO转接服务器

select实现多路IO转接服务器

基于该视频完成

15-select实现多路IO转接设计思路_哔哩哔哩_bilibili

通过响应式–多路IO转接实现

文章目录

  • select实现多路IO转接服务器
    • 1.思路&功能
    • 2.代码实现
      • warp.h
      • warp.c
      • multi_select_sever.c
      • 运行图
    • 3.代码解释(细节)
    • 4.改进版

1.思路&功能

**功能:**客户端输入小写字符串,服务器转成大写返回给客户端

思路:

image-20241212201548394

allset是用来更新rset的,因为rest是传入传出参数,allset是记录传出的rest的,因为rest传出以后,监听列表就变了,可能不会原来的了

2.代码实现

warp.h

#ifndef __WRAP_H_
#define __WRAP_H_
#include<sys/epoll.h>
//#include<event2/event.h>
#include<sys/select.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<string.h>
#include<dirent.h>
#include<sys/stat.h>
#include<wait.h>
#include<sys/mman.h>
#include<signal.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<ctype.h>
#include<strings.h>
#include<netinet/ip.h>
#define SRV_PORT 1234void perr_exit(const char *s);
int Accept(int fd,struct sockaddr *sa,socklen_t * salenptr);
int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
int Connect(int fd, const struct sockaddr *sa, socklen_t addrlen);
int Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
size_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd,const void *ptr,size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
ssize_t my_read(int fd, char  *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen);#endif

warp.c

#include"warp.h"void perr_exit(const char *s)
{perror(s);exit(1);
}int Accept(int fd,struct sockaddr *sa,socklen_t * salenptr)
{int n;
again:if((n=accept(fd,sa,salenptr))<0){if((errno==ECONNABORTED)||(errno==EINTR))goto again;elseperr_exit("accept error");}return n;
}int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{int n;if((n=bind(fd,sa,salen))<0)perr_exit("bind error");return n;
}int Connect(int fd, const struct sockaddr *sa, socklen_t addrlen)
{int n;n=connect(fd,sa,addrlen);if(n<0){perr_exit("connect error");}return n;
}int Listen(int fd, int backlog)
{int n;if((n=listen(fd,backlog))<0)perr_exit("listen error");return n;
}int Socket(int family, int type, int protocol)
{int n;if((n=socket(family,type,protocol))<0)perr_exit("socket error");return n;
}size_t Read(int fd, void *ptr, size_t nbytes)
{ssize_t n;
again:if((n=read(fd,ptr,nbytes))==-1){if(errno==EINTR)goto again;elsereturn -1;}return n;
}ssize_t Write(int fd,const void *ptr,size_t nbytes)
{ssize_t n;
again:if((n=write(fd,ptr,nbytes))==-1){if(errno==EINTR)goto again;elsereturn -1;}return 0;
}int Close(int fd)
{int n;if((n=close(fd))==-1)perr_exit("close error");return n;
}ssize_t Readn(int fd, void *vptr, size_t n)
{size_t nleft;ssize_t nread;char *ptr;ptr=vptr;nleft=n;while(nleft>0){if((nread=read(fd,ptr,nleft))<0){if(errno==EINTR)nread=0;elsereturn -1;}else if(nread==0)break;}
}
ssize_t Writen(int fd, const void *vptr, size_t n)
{size_t nleft;ssize_t nwritten;char *ptr;ptr=(char *)vptr;nleft=n;while(nleft>0){if((nwritten=write(fd,ptr,nleft))<=0){if(nwritten<0&&errno==EINTR)nwritten=0;elsereturn -1;}nleft-=nwritten;ptr+=nwritten;}return n;
}ssize_t my_read(int fd, char  *ptr)
{static int read_cnt;static char *read_ptr;static char read_buf[100];if(read_cnt<=0){
again:if((read_cnt=read(fd,read_buf,sizeof(read_buf)))<0){if(errno==EINTR)goto again;return -1;}else if(read_cnt==0)return 0;read_ptr=read_buf;}read_cnt--;*ptr=*read_ptr++;return 1;
}ssize_t Readline(int fd, void *vptr, size_t maxlen)
{ssize_t n,rc;char c,*ptr;ptr=vptr;for(n=1;n<maxlen;n++){if((rc=my_read(fd,&c))==1){*ptr++=c;if(c=='\n')break;}else if(rc==0){*ptr=0;return n-1;}else	return -1;}*ptr=0;return n;
}

multi_select_sever.c

#include"warp.h"
#define SERV_PORT 1234int main(int argc,char * argv[])
{int listenfd=0,connfd=0;int ret,maxfd=0,i,n,j;char buf[4096];listenfd=Socket(AF_INET,SOCK_STREAM,0);	struct sockaddr_in serv_addr,clie_addr;socklen_t clie_addr_len;serv_addr.sin_family=AF_INET;serv_addr.sin_port=htons(SERV_PORT);serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);Bind(listenfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));Listen(listenfd,128);fd_set rset,allset;FD_ZERO(&allset);FD_SET(listenfd,&allset);maxfd=listenfd;while(1){rset=allset;	ret=select(maxfd+1,&rset,NULL,NULL,NULL);if(ret<0)perr_exit("select error");if(FD_ISSET(listenfd,&rset)){clie_addr_len=sizeof(clie_addr);connfd=Accept(listenfd,(struct sockaddr *)&clie_addr,&clie_addr_len);FD_SET(connfd,&allset);if(maxfd<connfd)maxfd=connfd;if(ret==1)continue;}for(i=listenfd+1;i<=maxfd;i++){if(FD_ISSET(i,&rset)){n=read(i,buf,sizeof(buf));if(n==0){close(i);FD_CLR(i,&allset);}else if(n==-1)perr_exit("read error");}for(j=0;j<n;j++)buf[j]=toupper(buf[j]);Write(i,buf,n);Write(STDOUT_FILENO,buf,n);}}	Close(listenfd);return 0;
}
gcc warp.c multi_select_sever.c -o multi_select_sever

运行图

两个客户端访问服务器端

image-20241212205700368

3.代码解释(细节)

1.allset作用

更新rest,因为rest是传入传出参数,传出的是需要监听的集合

而需要监听的集合可能会改变,就是上一次监听的这一次来了可能就不需要监听了

2.监听套接字收到连接请求是属于读行为的,也就是说监听套接字要放到读集合中,有请求要连接的时候,传出的集合中会有监听套接字

3.如果有监听套接字,那说明有连接请求,我们就要处理连接

同时还要看传出的需要监听的描述符集合的大小,如果就是1,说明就只有一个连接请求,我们也就不需要执行下面的代码直接continue就行

4.如果传出的传出的需要监听的描述符集合的大小>1

那我们就循环遍历,从监听套接字开始,到最大

我们监听的是读集合,那如果文件描述在读集合中,那就读取数据然后小写转大写

如果对端关闭的话(read返回0),那就关闭连接同时清除掉该文件描述符

5.我们会发现我们没有用fork也没有用pthread就完成了多并发服务器

4.改进版

如果只有两个描述符,一个3,一个1023,那么效率会很低,我们现在用一个数组来把我们要监听的文件描述符存起来,然后遍历这个数组就行

其实就是比原来来说,避免了3和1023这种情况导致的效率降低的问题,总体效率并没有提升很多

#include"warp.h"
#define SERV_PORT 1234int main(int argc,char * argv[])
{int listenfd=0,connfd=0,maxfd,sockfd;int ret,i,n,j,maxi;char buf[4096],str[INET_ADDRSTRLEN];int nready,client[FD_SETSIZE];//就是个1024listenfd=Socket(AF_INET,SOCK_STREAM,0);	int opt=1;setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));struct sockaddr_in serv_addr,clie_addr;socklen_t clie_addr_len;serv_addr.sin_family=AF_INET;serv_addr.sin_port=htons(SERV_PORT);serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);Bind(listenfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));Listen(listenfd,128);fd_set rset,allset;FD_ZERO(&allset);FD_SET(listenfd,&allset);maxfd=listenfd;maxi=-1;for(i=0;i<FD_SETSIZE;i++)client[i]=-1;while(1){rset=allset;	nready=select(maxfd+1,&rset,NULL,NULL,NULL);if(nready<0)perr_exit("select error");if(FD_ISSET(listenfd,&rset)){clie_addr_len=sizeof(clie_addr);connfd=Accept(listenfd,(struct sockaddr *)&clie_addr,&clie_addr_len);printf("received from %s at PORT %d\n",inet_ntop(AF_INET,&clie_addr,str,sizeof(str)),ntohs(clie_addr.sin_port));for(i=0;i<FD_SETSIZE;i++)if(client[i]<0){client[i]=connfd;break;}if(i==FD_SETSIZE){fputs("too many clients\n",stderr);exit(1);}FD_SET(connfd,&allset);if(maxfd<connfd)maxfd=connfd;if(i>maxi)maxi=i;if(--nready==0)continue;}for(i=0;i<=maxi;i++){if((sockfd=client[i])<0)continue;if(FD_ISSET(sockfd,&rset)){n=read(sockfd,buf,sizeof(buf));if(n==0){close(sockfd);FD_CLR(sockfd,&allset);client[i]=-1;}else if(n>0){for(j=0;j<n;j++)buf[j]=toupper(buf[j]);Write(sockfd,buf,n);Write(STDOUT_FILENO,buf,n);}if(--nready==0)break;}}}	Close(listenfd);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/488554.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【有啥问啥】大语言模型Prompt中的“System指令”:深入剖析与误区澄清

大语言模型Prompt中的“System指令”&#xff1a;深入剖析与误区澄清 引言 在与大语言模型&#xff08;LLM&#xff09;交互时&#xff0c;“prompt”&#xff08;提示符&#xff09;这一概念已不再陌生。Prompt是引导模型生成特定类型文本的关键输入&#xff0c;决定了模型的…

【大模型】ChatGPT 创作各类高质量文案使用详解

目录 一、前言 二、ChatGPT文案创作的优势 三、ChatGPT 各类文案创作操作实战 3.1 ChatGPT创作产品文案 3.1.1 ChatGPT创作产品文案基本思路 3.1.2 ChatGPT 创作产品文案案例一 3.1.2.1 操作过程 3.1.3 ChatGPT 创作产品文案案例二 3.2 ChatGPT 创作视频脚本 3.2.1 Ch…

前端自己也能开启HTTPS

目录 前言 使用mkcert 安装 创建证书 利用 mkcert 创建 ca 根据 ca 创建 cert 安装证书 项目开启HTTPS 安装插件 配置 vitecofnig.js 最终效果 前言 今天我发现了一个宝藏&#xff0c;兄弟们&#xff01;就是前端开发阶段是可以使用https来开发的。对不懂前端的后端兄…

预言机调研

预言机 1. 概述 预言机主要承担两个工作&#xff0c;一是验证信息可靠性&#xff0c;二是传递信息。 如果没有预言机&#xff0c;区块链的信息来源将仅限于其内部数据&#xff0c;其广泛使用的潜力和可能性将会大大降低。 区块链预言机是区块链与外部世界之间的桥梁。它们使区…

Geometric Estimation via Robust Subspace Recovery_译文ECCV2020

目录 摘要&#xff1a; 1 引言 2 相关工作 3 方法 3.1 DLT 简介 3.2 鲁棒泛化 3.3 线性结构的扩展探索 3.4 实现细节 4 实验结果 4.1 线性嵌入的定性分析 4.2 基本和单应性估计 4.3 对离群值率的敏感性 5 结论 摘要&#xff1a; 根据图像点对应关系进行几何估计是许多 …

Linux入门攻坚——41、Linux集群系统入门-lvs(2)

lvs-dr&#xff1a;GATEWAY Director只负责请求报文&#xff0c;响应报文不经过Director&#xff0c;直接由RS返回给Client。 lvs-dr的报文路线如上图&#xff0c;基本思路就是报文不会回送Director&#xff0c;第①种情况是VIP、DIP、RIP位于同一个网段&#xff0c;这样&…

中粮凤凰里共有产权看房记

中粮凤凰里看房是希望而来&#xff0c;失望而归。主要是对如下失望&#xff0c;下述仅个人看房感受&#xff1a; 1. 户型不喜欢&#xff1a;三房的厨房和餐厅位置很奇葩 2. 样板间在25楼&#xff1a;湖景一言难尽和有工厂噪声 3. 精装修的交房质量:阳台的推拉门用料很草率 …

信奥赛CSP-J复赛集训(bfs专题)(5):洛谷P3395:路障

信奥赛CSP-J复赛集训&#xff08;bfs专题-刷题题单及题解&#xff09;&#xff08;5&#xff09;&#xff1a;洛谷P3395&#xff1a;路障 题目描述 B 君站在一个 n n n\times n nn 的棋盘上。最开始&#xff0c;B君站在 ( 1 , 1 ) (1,1) (1,1) 这个点&#xff0c;他要走到 …

OpenCV的图像矫正

一、原理 图像矫正的原理是透视变换&#xff0c;下面来介绍一下透视变换的概念。 透视变换&#xff08;Perspective Transform&#xff09;基于一个4对点的映射关系&#xff08;4个源点到4个目标点&#xff09;&#xff0c;通过这些点之间的映射&#xff0c;可以计算一个变换…

vscode 打开 setting.json

按下Ctrl Shift P&#xff08;Windows/Linux&#xff09;或Cmd Shift P&#xff08;Mac&#xff09;来打开命令面板。输入open settings&#xff0c;然后选择 Open User Settings(JSON)。打开settings.json文件 ------修改设置-----&#xff1a; 1、 html代码的行长度&am…

打电话玩手机识别-支持YOLO,COCO,VOC格式的标记,超高识别率可检测到手持打电话, 非接触式打电话,玩手机自拍等

打电话玩手机识别-支持YOLO&#xff0c;COCO&#xff0c;VOC格式的标记&#xff0c;超高识别率可检测到手持打电话&#xff0c; 非接触式打电话&#xff0c;玩手机自拍等1275个图片。 手持打电话&#xff1a; 非接触打电话 玩手机 数据集下载 yolov11:https://download.csdn…

外卖开发(八)—— SpringTask(定时任务) 和 WebSocket网络协议

外卖开发&#xff08;八&#xff09;—— SpringTask 和 WebSocket 一、利用SpringTask完成定时任务1、cron表达式2、springtask实现 二、使用webSocket实现接单、催单提醒1、代码分析2、催单提醒 一、利用SpringTask完成定时任务 Spring Task是Spring框架提供的任务调度工具&…

嵌入式系统中的并行编程模型:汇总解析与应用

概述&#xff1a;随着嵌入式系统处理能力的不断提升&#xff0c;并行编程在其中的应用愈发广泛。本文深入探讨了多种专门为嵌入式设计的并行编程模型&#xff0c;包括任务队列模型、消息传递模型、数据并行模型、异构多核并行模型、实时任务调度模型以及函数式并行模型。详细阐…

MTK 配置文件梳理

文章目录 MTK 日常配置总结屏幕默认横竖屏显示ro.build.characteristics 属性修改修改点一&#xff1a;build\core\product_config.mk修改点二&#xff1a;build\make\core\main.mk修改是否成功&#xff0c;adb 验证 配置部分系统app handheld_product.mk配置系统属性、第三方应…

CentOS 上如何查看 SSH 服务使用的端口号?

我们知道&#xff0c;linux操作系统中的SSH默认情况下&#xff0c;端口是使用22&#xff0c;但是有些线上服务器并不是使用的默认端口&#xff0c;那么这个时候&#xff0c;我们应该如何快速知道SSH使用的哪个端口呢&#xff1f; 1、通过配置文件查看 cat /etc/ssh/sshd_confi…

关于Redis哨兵机制实验操作步骤

需要搭建帮助的可以去taobao搜索Easy Company技术服务&#xff0c;谢谢&#xff01;&#xff01;&#xff01; 需要搭建帮助的可以去taobao搜索Easy Company技术服务&#xff0c;谢谢&#xff01;&#xff01;&#xff01; 一、配置哨兵(sentinel) 创建三个哨兵配置文件&…

Vue 集成地图

电子地图应用广泛&#xff1a; 网约车 : 在网约车 场景中实现 准定位 、导航 、司乘同显 &#xff0c;精准计费 智慧物流、生活服务等&#xff0c;本专题课程囊括各类应用场景 学习 电子地图解决方案&#xff0c;满足学员工作学习各类需求。 基础知识 学习 集成 地图之前需…

Qt-chart 画折线图(文字x轴)

图 代码 QLineSeries *seriesReality new QLineSeries();seriesReality->setColor(Qt::green);QLineSeries *seriesTar new QLineSeries();seriesTar->setColor(Qt::yellow);// 创建并配置X轴&#xff08;文字标签&#xff09;QStringList categories;for (int i 0; …

农业园区气象站

农业园区气象站是一种专为农业生产和科研设计的气象监测设备&#xff0c;它集成了多种传感器和技术&#xff0c;用于实时、准确地监测和记录农业园区内的气象数据。以下是农业园区气象站的主要功能和用处&#xff1a; 一、主要功能 实时监测&#xff1a;农业园区气象站能够实时…

DocFlow票据AI自动化处理工具:出色的文档解析+抽取能力,提升企业文档数字化管理效能

目录 财务应付 金融信贷业务 近期&#xff0c;DocFlow票据自动化产品正式上线。DocFlow是一款票据AI自动化处理工具&#xff0c;支持不同版式单据智能分类扩展&#xff0c;可选功能插件配置流程&#xff0c;满足多样业务场景。 随着全球化与信息化进程&#xff0c;企业的文件…