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

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;
}

相关文章:

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

select实现多路IO转接服务器 基于该视频完成 15-select实现多路IO转接设计思路_哔哩哔哩_bilibili 通过响应式–多路IO转接实现 文章目录 select实现多路IO转接服务器1.思路&功能2.代码实现warp.hwarp.cmulti_select_sever.c运行图 3.代码解释&#xff08;细节&#xf…...

基于前后端分离的食堂采购系统源码:从设计到开发的全流程详解

本篇文章&#xff0c;笔者将从系统设计到开发的全过程进行详解&#xff0c;帮助开发者和企业了解如何高效构建一套完善的食堂采购系统。 一、系统需求分析 在开发一套基于前后端分离的食堂采购系统前&#xff0c;必须对业务需求和功能模块进行详细分析&#xff0c;确保系统设…...

小程序自定义tab-bar,踩坑记录

从官方下载代码 https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html 1、把custom-tab-bar 文件放置 pages同级 修改下 custom-tab-bar 下的 JS文件 Component({data: {selected: 0,color: "#7A7E83",selectedColor: "#3…...

游戏引擎学习第52天

仓库 : https://gitee.com/mrxiao_com/2d_game 这节的内容相当多 回顾 在游戏中&#xff0c;实体被分为不同的类别&#xff1a;接近玩家的“高频实体”、距离较远并正在模拟的“低频实体”和不进行更新的“休眠实体”。这些实体会根据它们与玩家的距离进行处理&#xff0c;接…...

【热力学与工程流体力学】流体静力学实验,雷诺实验,沿程阻力实验,丘里流量计流量系数测定,局部阻力系数的测定,稳态平板法测定材料的导热系数λ

关注作者了解更多 我的其他CSDN专栏 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控制 传感器技术 嵌入式系统 复变函数与积分变换 单片机原理 线性代数 大学物理 热工与工程流体力学 数字信号处理 光电融合集成电路…...

【HTML】根据不同域名设置不同的网站图标(替换 link 中 href 地址)

文章目录 代码实现 <!DOCTYPE html> <html><head><meta charset"utf-8" /><meta http-equiv"x-ua-compatible" content"ieedge,chrome1" /><meta name"viewport" content"widthdevice-width&q…...

使用Navicat从SQL Server导入表数据到MySQL

在表上右键选择导入向导 选择ODBC 1.内输入ip即可&#xff0c;不需要端口号 一定要勾选允许保存密码 选择需要的表&#xff0c;下一步 根据需求&#xff0c;可修改表名、是否新建表 根据需求修改不同表的字段类型和长度 按需选择导入方式...

私有云dbPaaS为何被Gartner技术成熟度曲线标记为“废弃”?

当云计算席卷而来&#xff0c;基于云基础设施的数据库部署也改变了数据库。在传统的私有化部署&#xff08;On-premises&#xff09;和公有云部署&#xff08;Public Cloud&#xff09;之间&#xff0c;不断融合的混合IT&#xff08;Mixed IT&#xff09;形式成为最常见的企业级…...

牛客网 SQL1查询所有列

SQL1查询所有列 select id,device_id,gender,age,university,province from user_profile 每日问题 C 中面向对象编程如何实现数据隐藏&#xff1f; 在C中&#xff0c;面向对象编程&#xff08;OOP&#xff09;通过封装&#xff08;Encapsulation&#xff09;实现数据隐藏。…...

【经验分享】OpenHarmony5.0.0-release编译RK3568不过问题(已解决)

问题描述 根据操作手册正常拉取代码&#xff0c;然后编译OpenHarmony5.0.0版本rk3568项目 编译命令 ./build.sh --product-name rk3568 --ccache出现如下报错 然后真正开始出错的位置是下面这句log FAILED: ../kernel/src_tmp/linux-5.10/boot_linux ../kernel/checkpoint/c…...

如何使用ERC404协议

ERC404 ERC404协议的性质 ERC404不是一个开发代码工具包,而是一种智能合约标准规范。它就像是一份蓝图或者规则手册,规定了在以太坊区块链上开发特定智能合约应该遵循的接口、函数和事件等规则。如何使用ERC404协议 定义合约接口 首先,在开发智能合约时,要根据ERC404标准定…...

240004基于Jamva+ssm+maven+mysql的房屋租赁系统的设计与实现

基于ssmmavenmysql的房屋租赁系统的设计与实现 1.项目描述2.运行环境3.项目截图4.源码获取 1.项目描述 该项目在原有的基础上进行了优化&#xff0c;包括新增了注册功能&#xff0c;房屋模糊查询功能&#xff0c;管理员和用户信息管理等功能&#xff0c;以及对网站界面进行了优…...

ORACLE RAC ADG备库报错ORA-04021: timeout occurred while waiting to lock object

问题&#xff1a;核心的灾备 RAC ADG 备库&#xff0c;这两天频繁重启&#xff0c;并且报如下错误&#xff0c;通过查看MOS&#xff0c;发现是个BUG ADG备库的ALERT错误日志如下&#xff1a; Errors in file /u01/app/oracle/diag/rdbms/hxxxsz/hxxxsz1/trace/hxxxsz1_lgwr_69…...

CAPL如何设置或修改CANoe TCP/IP协议栈的底层配置

在CANoe中创建网络节点作为以太网主机时,可以给其配置独立的TCP/IP Stack。 配置的协议栈有一些底层配置参数可以在界面上设置或修改,比如: MTU上图中MTU显示500只是图形界面显示错误,正确值是1500。 TCP延迟确认这些参数也可以通过CAPL动态配置,甚至CAPL还可以配置很多界…...

git使用教程(超详细)-透彻理解git

一.核心基础 核心概念有六个 首先请把与svn有关的一切概念暂时从你的脑海中移除掉&#xff0c;我们要重新认识本文所讲述的所有概念。 1.worktree worktree是一个目录&#xff0c;你在这里对文件进行增加、删除、修改。也就是我们常说的工作区。在git中worktree必须要与一个…...

【2024 Dec 超实时】编辑安装llama.cpp并运行llama

首先讲一下环境 这是2024 年12月&#xff0c;llama.cpp 的编译需要cmake 呜呜呜 网上教程都是make 跑的。反正我现在装的时候make已经不再适用了&#xff0c;因为工具的版本&#xff0c;捣鼓了很久。 ubuntu 18 conda env内置安装。 以下是可以完美编译llama.cpp的测试工具版…...

Docker介绍、安装、namespace、cgroup、镜像-Dya 01

0. 容器简介 从生活上来说&#xff0c;容器是一种工具&#xff0c;可以装东西的工具&#xff0c;如衣柜、背包、行李箱等等。 从IT技术方面来说&#xff0c;容器是一种全新的虚拟化技术&#xff0c;它提高了硬件资源利用率&#xff0c;结合k8s还可以让企业业务快速横向扩容、业…...

docker 搭建自动唤醒UpSnap工具

1、拉取阿里UpSnap镜像 docker pull crpi-k5k93ldwfc7o75ip.cn-hangzhou.personal.cr.aliyuncs.com/upsnap/upsnap:4 2、创建docker-compose.yml文件&#xff0c;进行配置&#xff1a; version: "3" services:upsnap:container_name: upsnapimage: crpi-k5k93ldwf…...

3D一览通在线协同设计,助力汽车钣金件设计与制造数字化升级

汽车行业已迎来智能化的汹涌浪潮&#xff0c;在此背景下&#xff0c;零部件制造商唯有积极应对&#xff0c;以智能制造为核心驱动力&#xff0c;方能跟上行业发展步调&#xff0c;在激烈的市场竞争中抢占先机。作为整车制造不可或缺的核心组件之一&#xff0c;汽车钣金件亦需紧…...

基于Matlab实现三维地球模型(源码)

利用MATLAB强大的图形处理能力和数学计算功能构建的可视化应用。这个模型允许用户在三维空间中观察地球&#xff0c;并且能够动态地旋转地球模型&#xff0c;同时还可以模拟卫星在其周围的运动轨迹&#xff0c;为学习地球科学、天文学以及航天工程等领域提供了一个直观的教学工…...

【Tomcat】第五站:Servlet容器

Tomcat启动后&#xff0c;获取到项目当中所有的servlet的WebServlet中的配置信息。将配置信息和类对象都写入一个map集合当中。 map就是一个key-value类型的集合。 在MyTomcat中我们获取到了类对象和注解值。 Tomcat与请求连通 1. ServletConfigMapping 1. 创建一个config包…...

CTF 攻防世界 Web: FlatScience write-up

题目名称-FlatScience 网址 index 目录中没有发现提示信息&#xff0c;链接会跳转到论文。 目前没有发现有用信息&#xff0c;尝试目录扫描。 目录扫描 注意到存在 robots.txt 和 login.php。 访问 robots.txt 这里表明还存在 admin.php admin.php 分析 在这里尝试一些 sql…...

【SpringBoot中MySQL生成唯一ID的常见方法】

SpringBoot中MySQL生成唯一ID的常见方法 在Spring Boot中&#xff0c;为MySQL生成唯一ID有多种方式&#xff0c;每种方式都有其特定的概念、优越点和使用场景。以下是详细的说明和代码示例&#xff1a; UUID 概念: UUID&#xff08;Universally Unique Identifier&#xff0…...

使用Flink CDC实现 Oracle数据库数据同步的oracle配置操作

使用Flink CDC实现 Oracle数据库数据同步的oracle配置操作&#xff0c;包括开启日志归档和用户授权。 flink官方参考资料&#xff1a; https://nightlies.apache.org/flink/flink-cdc-docs-master/zh/docs/connectors/flink-sources/oracle-cdc/ 操作步骤&#xff1a; 1.启用…...

c++作业7

模拟一个游戏场景 有一个英雄&#xff1a;初始所有属性为1 atk,def,apd,hp 游戏当中有以下3种武器 长剑Sword&#xff1a; 装备该武器获得 1atx&#xff0c;1def 短剑Blade&#xff1a; 装备该武器获得 1atk&#xff0c;1spd 斧头Axe&#xff1a; 装备该…...

vue 上传组件 vxe-upload 实现拖拽调整顺序

vue 上传组件 vxe-upload 实现拖拽调整顺序&#xff0c;通过设置 drag-sort 参数就可以启用拖拽排序功能 官网&#xff1a;https://vxeui.com/ 图片拖拽排序 <template><div><vxe-upload v-model"imgList" mode"image" multiple drag-sor…...

Windows 环境实战开源项目GFPGAN 教程

GFPGAN GFPGAN&#xff08;Generative Facial Prior-GAN&#xff09;是由腾讯ARC&#xff08;Applied Research Center&#xff09;开发的一种实用的真实世界人脸修复算法。它专门设计用于人脸图像的生成和优化&#xff0c;尤其在低质量人脸图像的超分辨率恢复方面表现出色。以…...

UE5 做简单的风景观光视频

A、思路 新建摄像机&#xff0c;关卡序列&#xff0c; 镜头试拍录制器&#xff0c;新建镜头轨道&#xff0c;拖入摄像机&#xff0c; 变换&#xff0c;设置多个关键帧&#xff0c;改变摄像机在场景中的位置&#xff0c; 完成后&#xff0c;导出即可。 B、参考图...

k8s服务搭建与实战案例

Kubernetes&#xff08;K8s&#xff09;作为一个开源的容器编排平台&#xff0c;广泛应用于现代的云原生应用架构中。以下是一些常见的 **Kubernetes 实战案例**&#xff0c;包括从基础部署到高级应用场景的使用。通过这些案例&#xff0c;可以更好地理解 K8s 的运作原理和最佳…...

JavaScript学习难点

一、语法的灵活性 动态类型&#xff1a; JavaScript 是一种动态类型语言&#xff0c;这意味着变量的类型可以在运行时改变。这与静态类型语言&#xff08;如 Java、C&#xff09;形成鲜明对比&#xff0c;在静态类型语言中&#xff0c;变量的类型在编译时就已经确定。 例如&am…...