多路I/O转接服务器

2023-10-27

多路IO转接服务器也叫做多任务IO服务器。该类型服务器实现的主旨思想是,不在由应用程序自己监视连接,取而代之由内核替应用程序监视文件
主要使用方法有三种

1、select函数

1、select 能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开的文件描述符个数能改变select监听文件个数
2、解决1024以下客户端时使用select是很合适的,但如果连接客户端过多,select采用的是轮询模型,会大大降低服务器响应效率

#include<sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int nfds,fd_set *readfds,fd_set *writefds,\
				fd_set *exceptfds,struct timeval *timeout);

nfds:监控的文件描述符集里最大文件描述符加1,因为此参数会告诉内核检测前多少个文件描述符的状态
readfds:监控有读数据到到文件描述符集合,传入传出参数
writefds:监控写数据到达文件描述符集合,传入传出参数
exceptfds:监控异常发生文件描述符集合,如带外数据到达异常,传入传出参数
timeout:定时阻塞监控时间,3种情况
1、NULL,永远等下去
2、设置timeval,等待固定时间
3、设置timeval里时间均为0,检查描述字后立即返回,轮询

struct timeval{
	long tv_sec; /*seconds*/
	long tv_usec;/*microseconds*/
};
void FD_CLR(int fd,fd_set *set);//把文件描述符集合里fd清0
int FD_ISSET(int fd,fd_set *set);//测试文件描述符集合里fd是否置1
void FD_SET(int fd,fd_set*set);//把文件描述符集合里fd置1
void FD_ZERO(fd_set *set);//把文件描述符集合里所有位清0

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MAXLINE 80
#define SERV_PORT 6666

int main(argc,argv[])
{
	int i,maxi,maxfd,listenfd,connfd,sockfd;
	int nready,client[FD_SETSIZE];/*FD_SETSIZE 默认为1024*/
	ssize_t n;
	fd_set rset,allset;
	char buf[MAXLINE];
	char str[INET_ADDRSTRLEN]; /*#define INET_ADDRSTRLEN 16*/
	socklen_t cliaddr_len;
	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 = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);
	bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
	listen(listenfd,20); 
	maxfd = listenfd; //初始化
	maxi = -1; //client[]的下标
	
	for(i=0;i<FD_SETSIZE;i++)
	{
		client[i] = -1;//用-1初始化client[]
	}
	FD_ZERO(&allset);
	FD_SET(listenfd,&allset);
	for(;;){
		rset = allset;
		nready = select(maxfd+1,&rset,NULL,NULL,NULL);
		if(nready < 0)
		{perr_exit("select error");}
		if(FD_ISSET(listenfd,&rset)){ /*new clinet connection*/
			cliaddr_len = sizeof(cliaddr);
			connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&cliaddr_len);
			printf("received from %s at PORT %d\n",
						inet_ntop(AF_INET,&cliaddr.sin_addr,str,sizeof(str)),
						ntohs(cliaddr.sin_port);
			for(i = 0;i<FD_SETSIZE;i++){
				if(client[i]<0){
				client[i] = connfd;/*保存accept返回的文件描述符到client[]里*/
				break;
				}
			}
			/*达到select能监控的文件个数上限1024*/
			if(i == FD_SETSIZE){
				fputs("two many clients\n",stderr);
				exit(1);
			}
			FD_SET(connfd,&allset);/*添加一个新的文件描述符到监控信号集里*/
			if(confd>maxfd)
			{maxfd = connfd;}/*select 第一个参数需要*/
			if(i>maxi)
				maxi = i; /*更新client[]最大下标值*/
			if(--nready == 0)
			{continue;}/*如果没有更多的就绪文件描述符继续回到上面select阻塞监听,负责处理未处理完的就绪文件描述符*/					
		}
		for(i=0;i<=maxi;i++){/*检测哪个clients有数据就绪*/
			if((sockfd = client[i])<0)
				{continue;}
			if(FD_ISSET(sockfd,&rset)){
				if((n==read(sockfd,buf,MAXLINE))==0){
					close(sockfd); /*当client关闭连接时,服务器端也关闭对应连接*/
					FD_CLR(sockfd,&allset);/*解除select监控此文件描述符*/
					client[i] = -1;
				}else{
					int j;
					for(j=0;j<n;j++)
					{buf[j] =toupper(buf[j]);}
					write(sockfd,buf,n);
				}
				if(--nready == 0)
				break;
			}
		}
	}
	close(listenfd);
	return 0;
}

client.c

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include "wrap.h"

#define MAXLINE 80
#define SERV_PORT 6666

int main(int argc, char *argv[])
{
	struct sockaddr_in servaddr;
	char buf[MAXLINE];
	int sockfd, n;
sockfd = socket(AF_INET, SOCK_STREAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
	servaddr.sin_port = htons(SERV_PORT);

	connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

	while (fgets(buf, MAXLINE, stdin) != NULL) {
		write(sockfd, buf, strlen(buf));
		n = read(sockfd, buf, MAXLINE);
		if (n == 0)
			printf("the other side has been closed.\n");
		else
			write(STDOUT_FILENO, buf, n);
	}
	close(sockfd);
	return 0;
}

2 poll函数

#include <poll.h>
int poll(struct pollfd *fds,nfds_t nfds,int timeout);

struct pollfd{
	int fd;/*文件描述符*/
	short events;/*监控事件*/
	short revents; /*监控事件中满足条件返回的事件*/
}

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#incldue <poll.h>
#include <errno.h>

#define MAXLINE 80
#define SERV_PORT 5000
#define OPEN_MAX 1024

int main (int argc,char *argv[])
{
	int i,j,maxi,listenfd,connfd,sockfd;
	int nready;
	ssize_t n;
	char buff[MAXLINE],str[INET_ADDRSTRLEN];
	socklen_t clilen;
	struct pollfd client[OPEN_MAX];
	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 = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);
	
	bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));

	listen(listenfd,20);
	
	client[0].fd = listenfd;
	client[0].events = POLLRDNORM; /*listenfd 监听普通读事件*/
	
	for(i = 1;i<OPEN_MAX;i++)
	{clent[i].fd = -1}/*用-1初始化client[]里剩下元素*/
	maxi = 0;

	for(;;)
	{
		nready = poll(client,maxi=1-1); //阻塞
		if(client[0].revents & POLLRDNORM){
			clilen = sizeof(cliaddr);
			connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
			printf("received from %s at PORT %d\n",\
				inet_ntop(AF_INET,&cliaddr.sin_addr,str,sizeof(str)),\
				ntohs(cliaddr.sin_port);)
			for(i = 1;i<OPEN_MAX;i++){
				if(client[i].fd < 0){
					client[i].fd = connfd;/*找到client[]中空闲的位置,存放accept返回的connfd*/
					break;
				}
			}
			if(i == OPEN_MAX)
			{perr_exit("too many clients");}
			
			client[i].events = POLLRONOM;/*设置刚刚返回的connfd,监控读事件*/
			
			if(i > maxi)
			{maxi = i;}/*更新client[]中最大元素下标*/
			
			if(--nready <= 0)
			{continus;}/*没有更多就绪事件时,继续回到poll阻塞*/
		}
		for(i = 1;i<maxi;i++){ /*检测client[]*/
			if((sockfd = client[i].fd) < 0)
			{continue;}
			if(client[i].revents & (POLLRDNORM | POLLERR)){
				if((n=read(sockfd,buf,MAXLINE)) < 0){
					if(errno == ECONNRESET){/*当收到RST标志时*/
							/*connection reset by client*/
							printf("client[%d aborted connection\n",i);
							close(sockfd);
							client[i].fd = -1;
					}else{
						perr_exit("read error");
					}
				}else if (n == 0){
					/*connection closed by client*/
					printf("client[%d] closed connection\n",i);
					close(sockfd);
					client[i].fd = -1;
				}else{
						for(j=0;j<n;j++)
						{buf[j]=toupper(buf[j]);}
						write(sockfd,buf,n);
				}
				if(--nready<=0)
				{break;}/*no more readable descriptors*/
			}
		}
	}
	return 0;
}

cleint.c

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>

#define MAXLINE 80
#define SERV_PORT 5000

int main (int argc,char *argv[])
{
	struct sockaddr_in servaddr;
	char buf[MAXLINE];
	int sockfd,n;

	sockfd = socket(AF_INET,SOCK_STREAM,0);
	bzero(&servaddr,sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	int_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr);
	servaddr.sin_port = htons(SERV_PORT);
	
	connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));

	while(fgets(buf,MAXLINE,stdin)!= NULL){
		write(sockfd,buf,strlen(buf));
		n = read(sockfd,buf,MAXLINE);
		if(n == 0)
		{printf("the other side has benn closed.\n");}
		else
		{write(STDOUT_FILENO,buf,n);}
	}
	close(sockfd);
	return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

多路I/O转接服务器 的相关文章

  • ssh 连接超时

    我无法在 git 中 ssh 到 github bitbucket 或 gitlab 我通常会收到以下错误消息 如何避免它 输出 ssh T email protected cdn cgi l email protection i ssh
  • vmsplice() 和 TCP

    在原来的vmsplice 执行 有人建议 http lwn net Articles 181169 如果您的用户态缓冲区是管道中可容纳的最大页面数的 2 倍 则缓冲区后半部分成功的 vmsplice 将保证内核使用缓冲区的前半部分完成 但事
  • 找不到包“gdk-pixbuf-2.0”

    我正在尝试在 Amazon Linux 发行版实例上构建 librsvg 我已经通过 yum 安装了大部分依赖项 其中一些在实例上启用的默认 yum 存储库中不可用 因此必须从头开始构建它们 我已经走了很远 但还停留在最后一点 跑步时sud
  • 仅使用containerd(不使用Docker)修剪容器镜像

    如果我刚刚containerd安装在 Linux 系统上 即 Docker 是not安装 如何删除未使用的容器映像以节省磁盘空间 Docker 就是这么方便docker system prune https docs docker com
  • 在 .gitconfig 中隐藏 GitHub 令牌

    我想将所有点文件存储在 GitHub 上 包括 gitconfig 这需要我将 GitHub 令牌隐藏在 gitconfig 中 为此 我有一个 gitconfig hidden token 文件 这是我打算编辑并放在隐藏令牌的 git 下
  • 使用 \r 并打印一些文本后如何清除控制台中的一行?

    对于我当前的项目 有一些代码很慢并且我无法使其更快 为了获得一些关于已完成 必须完成多少的反馈 我创建了一个进度片段 您可以在下面看到 当你看到最后一行时 sys stdout write r100 80 n I use 80覆盖最终剩余的
  • 如何使用 Cloud Init 挂载未格式化的 EBS 卷

    Context 我正在使用https wiki jenkins io display JENKINS Amazon EC2 Plugin https wiki jenkins io display JENKINS Amazon EC2 Pl
  • linux-x64 二进制文件无法在 linuxmusl-x64 平台上使用错误

    我正在安装Sharp用于使用 package json 的 Nodejs 项目的 docker 映像上的映像压缩包 当我创建容器时 我收到有关 Sharp 包的以下错误 app node modules sharp lib libvips
  • GMail 421 4.7.0 稍后重试,关闭连接

    我试图找出为什么它无法使用 GMail 从我的服务器发送邮件 为此 我使用 SwiftMailer 但我可以将问题包含在以下独立代码中
  • C 语言的符号表

    我目前正在开发一种执行模式匹配的静态分析工具 我在用Flex https github com westes flex生成词法分析器 我编写了代码来管理符号表 我不太有经验C 所以我决定将符号表实现为线性链表 include
  • 使用 MAX_ORDER / 包含 mmzone.h

    根据https www kernel org doc Documentation networking packet mmap txt https www kernel org doc Documentation networking pa
  • 如何使用waf构建共享库?

    我想使用构建一个共享库waf http code google com p waf 因为它看起来比 GNU 自动工具更容易 更简洁 到目前为止 我实际上有几个与我开始编写的 wscript 有关的问题 VERSION 0 0 1 APPNA
  • 与 pthread 的进程间互斥

    我想使用一个互斥体 它将用于同步对两个不同进程共享的内存中驻留的某些变量的访问 我怎样才能做到这一点 执行该操作的代码示例将非常感激 以下示例演示了 Pthread 进程间互斥体的创建 使用和销毁 将示例推广到多个进程作为读者的练习 inc
  • 为什么opencv videowriter这么慢?

    你好 stackoverflow 社区 我有一个棘手的问题 我需要你的帮助来了解这里发生了什么 我的程序从视频采集卡 Blackmagic 捕获帧 到目前为止 它工作得很好 同时我用 opencv cv imshow 显示捕获的图像 它也工
  • 错误:“rjags”的包或命名空间加载失败

    在终端的 conda 环境之一中 我能够成功安装包 rjags 但是 当我在该环境中运行 R 并运行库 rjags 时 出现以下错误 加载所需的包 coda 错误 rjags 的包或命名空间加载失败 rjags 的 loadNamespac
  • 在生产服务器上使用 Subversion 使文件生效的最佳方法是什么?

    目前我已经设置了 subversion 这样当我在 Eclipse PDT 中进行更改时 我可以提交更改 它们将保存在 home administrator 中项目文件 该文件具有 subversion 推荐的 branches tags
  • Linux 为一组进程保留一个处理器(动态)

    有没有办法将处理器排除在正常调度之外 也就是说 使用sched setaffinity我可以指示线程应该在哪个处理器上运行 但我正在寻找相反的情况 也就是说 我想从正常调度中排除给定的处理器 以便只有已明确调度的进程才能在那里运行 我还知道
  • 如何让 Node.js 作为后台进程运行并且永不死掉?

    我通过 putty SSH 连接到 linux 服务器 我尝试将其作为后台进程运行 如下所示 node server js 然而 2 5 小时后 终端变得不活动 进程终止 即使终端断开连接 我是否也可以使进程保持活动状态 Edit 1 事实
  • 从 Linux 内核模块中调用用户空间函数

    我正在编写一个简单的 Linux 字符设备驱动程序 以通过 I O 端口将数据输出到硬件 我有一个执行浮点运算的函数来计算硬件的正确输出 不幸的是 这意味着我需要将此函数保留在用户空间中 因为 Linux 内核不能很好地处理浮点运算 这是设
  • x86-64 AMD 上 CALL 指令的操作数生成

    以下是示例程序 objdump 的输出 080483b4

随机推荐

  • 攻防世界新手区web simple_php

    simple php 不认识show source函数 百度一下 可知这个函数是对测试文件 test php 进行 PHP 语法高亮显示 可大致理解为提交a和b的正确形式可得到flag 百度可知is numeric函数判断是否为数字或数字字
  • 与众不同的协同办公工具——飞书

    其实很早就知道飞书 但真正深入了解 还是最近一个月的事情 因为一个知识付费产品的强烈推荐 我才真正试用了一下 试完之后 很有启发 觉得有必要整理和总结一下 以便后续继续深入使用 飞书有什么不同 我觉得有如下三点 第一 不一样的沟通方式 它力
  • windows使用命令行创建文件echo >test.txt(可以是.gp .js .ts..)

    或多说直接上代码 第一步 打开命令行 进入要创建的目录 C Users gt cd C Users lenovo Desktop node 第二步 输入创建文件的指令 echo gt 文件名字 文件名字 就是常见的文件 例如 txt js
  • 关于echarts中南海诸岛的显示问题

    关于echarts中南海诸岛的显示问题 1 china js 文件中 echarts registerMap china 名字要是 china 不能写成 中国 2 echarts 配置中地图名称 mapName china var myCh
  • sequence中实现寄存器前门访问的4种方法

    uvm sequence中实现寄存器访问的方法 在芯片的eda仿真过程中 有的场景需要在发包控制的时候对dut的寄存器进行一些动态配置 这就需要通过寄存器模型来对相关寄存器进行读写操作 小结三种方法如下 通过uvm top这个全局变量来获取
  • django系列 第一节

    一 安装python 安装django 使用虚拟环境 Virtualenv python3的安装方法 http blog csdn net xudailong blog article details 78309857 django的安装方
  • LeetCode(力扣) 312题:戳气球----动态规划求解附带详细注释

    问题描述 有n个气球 编号为 0 到 n 1 每个气球上都标有一个数字 这些数字存在于数组nums中 现在要求你戳破所有的气球 戳破第 i 个气球 你可以获得nums i 1 nums i nums i 1 枚硬币 这里的 i 1 和 i
  • linux给用户添加文件夹的使用权限

    添加权限 将目录 opt 及其下面的所有文件 子目录的文件主改成 liuhai chown R liuhai liuhai opt root localhost sudo chown R oracle home 选项 c或 changes
  • postgresql 服务无法启动,日志中报如下错误

    1 postgresql 服务无法启动 日志中报如下错误 磁盘空间足够 无法找到来自源 PostgreSQL 的事件 ID 0 的描述 本地计算机上未安装引发此事件的组件 或者安装已损坏 可以安装或修复本地计算机上的组件 1 使用pg co
  • 因特网中的电子邮件--应用层协议

    因特网中的电子邮件 因特网中的电子邮件系统主要由三部分组成 用户代理 user agent 邮件服务器 mail server 简单邮件传输协议 Simple Mail Transfer Protocol SMTP 邮件服务器为电子邮件系统
  • matlab计算数据MEA与RMSE误差指标

    MEA Mean Absolute Error 均方差 和RMSE Root Mean Square Error 均方根误差 是两个经常使用的误差评价指标 用于评价模型预测值与真实值之间的误差大如其间的误差 1 MEA 均方差 将预测结果与
  • fastadmin列表自动刷新功能

    在fastadmin框架中 将列表自动刷新给屏蔽了 如果要开启的话 有点麻烦 需要去重新修改框架核心的js代码 然后还需要重新进行编译 在看开发文档的时候 发现列表是存在refresh的方法 既然有这个方法在 那么是否能结合JS的定时器来做
  • 源码追踪,记typeAliasesPackage的使用(ruoyi-cloud中一个疑问的启发)

    首先 提一个思考题 在mapper xml文件中写sql的时候 parameterType指明入参类型的时候 为什么只需要写String Long Integer等 而不用写java lang String java lang Long这样
  • 又一新闻,Meta研发了超越chatGPT的新平台LLAMA

    一 Meta 全新大语言模型 LLaMA 正通过种子公开发放 2 月 24 日 Meta 公司发布了新的大模型系列 LLaMA Large Language Model Meta AI Meta 宣称 LLaMA 规模仅为竞争对手 Chat
  • POST请求错误 net::ERR_EMPTY_RESPONSE

    1 问题 最近在学习使用node js express写后台项目 首先Network发送options 成功 其后的post请求状态一直为pending 在网络上搜索许多方式未能解决 过了一段时间后未响应状态转为failed 2 解决 其状
  • Python:全局替换文件夹下所有文件内容的字符串

    代码参数详解 import os def listFiles dirPath 遍历指定文件夹下打印所有的文件 param dirPath 指定遍历的文件夹路径 return 一个列表 包含指定文件夹下所有的文件绝对路径 准备一个空列表 用来
  • 【Unity】热更新之xLua C#调用Lua / 自定义加载器 / 加载并执行AB包中的Lua文件

    最近在学习xLua 和大家分享一下学习笔记 下载xLua xLua的GitHub下载地址 xLua下载 GitHub 点击进入 点击链接进入后 首先点击Code 再点击Download ZIP把压缩包下载下来 下载完后解压得到xLua ma
  • K8s生产环境常见问题处理、答疑(连载、不定期更新)

    文章目录 K8s 常见问题处理 答疑 1 calico一直处于未就绪状态 2 删除dashboard 一直卡在delete 3 k8s dashboard 修改tocken ttl避免频繁输入tocken 4 kubectl 快捷指令 5
  • Separating Axis Theorem (SAT) Explanation

    Separating Axis Theorem SAT Explanation Posted on May 24 2009 Separating Axis Theorem SAT is a technique for calculating
  • 多路I/O转接服务器

    多路IO转接服务器也叫做多任务IO服务器 该类型服务器实现的主旨思想是 不在由应用程序自己监视连接 取而代之由内核替应用程序监视文件 主要使用方法有三种 1 select函数 1 select 能监听的文件描述符个数受限于FD SETSIZ