select完成服务器并发

news2024/11/26 2:00:42

服务器

#include <myhead.h>

#define PORT 4399 	//端口号
#define IP "192.168.0.191"//IP地址

//键盘输入事件
int keybord_events(fd_set readfds);
//客户端交互事件
int cliRcvSnd_events(int , struct sockaddr_in*, fd_set *, int *);
//客户端连接事件
int cliConnect_events(int , struct sockaddr_in*, fd_set *, int *);

int main(int argc, const char *argv[])
{
	//创建流式套接字
	int sfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("socket create success sfd=%d\n", sfd);

	//允许端口被快速复用
	int reuse = 1;
	if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
	{
		ERR_MSG("setsockopt");
		return -1;
	}
	//填充地址信息结构体
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;//必须填AF_INET
	sin.sin_port = htons(PORT);//端口号的网络字节序
	sin.sin_addr.s_addr = inet_addr(IP);//本机IP

	//绑定服务器的地址信息
	if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind success\n");
	//将套接字设置为被动监听状态
	if(listen(sfd, 128) < 0)
	{
		ERR_MSG("listen");
		return -1;
	}
	printf("listen success\n");
	//创建一个读集合,一个操作集合
	fd_set readfds, tempfds;

	//清空集合
	FD_ZERO(&readfds);

	//将需要监测的文件描述符加入读集合
	FD_SET(0, &readfds);
	FD_SET(sfd, &readfds);

	int maxfd = sfd; 	//存储最大的文件描述符
	int s_res = -1;
	ssize_t res = -1;
	char buf[128] = "";
	struct sockaddr_in saveCin[1024]; 	//备份连接成功的客户端的地址信息,且用下标对应文件描述符

	while(1)
	{
		tempfds = readfds;
		//执行多路复用函数
		s_res = select(maxfd+1, &tempfds, NULL, NULL, NULL);
		if(s_res < 0)
		{
			ERR_MSG("select");
			return -1;
		}
		else if(0 == s_res)
		{
			printf("time out...\n");
			break;
		}


		//此时代表select函数解除阻塞,集合中有文件描述符存在
		for(int i=0;i<=maxfd;i++)
		{
			if(FD_ISSET(i, &tempfds) == 0)

				continue;

			//此时代表i所对应的文件描述符在集合中
			if(0 == i)
			{
				keybord_events(readfds);
			}
			else if(sfd == i)//代表sfd在集合中
			{
				//	printf("触发客户端连接事件\n");
				cliConnect_events(sfd, saveCin, &readfds, &maxfd);
			}
			else
			{
				//	printf("触发客户端交互事件\n");
				cliRcvSnd_events(i, saveCin, &readfds, &maxfd);
			}
		}

	}

	if(close(sfd) < 0)
	{
		ERR_MSG("close");
		return -1;
	}



	return 0;
}

//键盘输入事件
int keybord_events(fd_set readfds)
{
	char buf[128] = "";
	int sndfd = -1;
	bzero(buf, sizeof(buf));

	int res = scanf("%d %s", &sndfd, buf);
	while(getchar() != 10);
	if(res != 2)
	{
		printf("输入数据的格式错误 :fd string\n");
		return -1;
	}

	if(sndfd<=2 || FD_ISSET(sndfd, &readfds) == 0)
	{
		printf("非法的文件描述符:sndfd=%d\n", sndfd);
		return -1;
	}

	if(send(sndfd, buf, sizeof(buf), 0) < 0)
	{
		ERR_MSG("send");
		return -1;
	}

	printf("send success\n");

	return 0;
}

//客户端连接事件
int cliConnect_events(int sfd, struct sockaddr_in saveCin[], fd_set *preadfds, int *pmaxfd)
{
	int newfd = -1;
	struct sockaddr_in cin;//存储客户端地址信息
	socklen_t addrlen = sizeof(cin); //真实的地址信息结构体的大小

	newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);
	if(newfd < 0)
	{
		ERR_MSG("newfd");
		return -1;
	}
	printf("[%s:%d]客户端连接成功 newfd=%d\n",\
			inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);
	saveCin[newfd] = cin; 	//将cin另存到newfd对应的下表位置
	FD_SET(newfd, preadfds); //将newfd添加到集合中
	*pmaxfd = *pmaxfd>newfd ? *pmaxfd:newfd; 	//更新maxfd

	return 0;
}

//客户端交互事件
int cliRcvSnd_events(int fd, struct sockaddr_in* saveCin, fd_set *preadfds, int *pmaxfd)
{
	char buf[128] = "";
	//清空字符串
	bzero(buf, sizeof(buf));

	//接收
	ssize_t res = recv(fd, buf, sizeof(buf), 0);
	if(res < 0)
	{
		ERR_MSG("recv");
		return -1;
	}
	else if(0 == res)
	{
		printf("[%s:%d]客户端下线 newfd=%d\n",\
				inet_ntoa(saveCin[fd].sin_addr), ntohs(saveCin[fd].sin_port), fd);
		close(fd);//关闭文件描述符
		FD_CLR(fd, preadfds); //将文件描述符从集合中删除

		//由于删除的文件描述符可能是最大的文件描述符,所以要更新maxfd
		while(FD_ISSET(*pmaxfd, preadfds) == 0 && (*pmaxfd)-- >= 0);
		return 0;
	}
	printf("[%s:%d] newfd=%d:%s\n",\
			inet_ntoa(saveCin[fd].sin_addr), ntohs(saveCin[fd].sin_port), fd, buf);

	//发送信息
	strcat(buf, "*_*");
	if(send(fd, buf, sizeof(buf), 0) < 0)
	{
		ERR_MSG("send");
		return -1;
	}
	printf("send success\n");
	return 0;
}

客户端

#include<myhead.h>

#define PORT 4399             //服务器绑定的端口号
#define IP  "192.168.0.191"   //服务器绑定的IP


int main(int argc, const char *argv[])
{
	//创建流式套接字 socket
	int cfd = socket(AF_INET, SOCK_STREAM, 0);
	if(cfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("socket create success cfd=%d\n", cfd);

	//绑定客户端的地址信息---》非必须绑定
	//当不手动绑定的时候,操作系统会自动给客户端绑定本机IP和随机端口。   


	//填充服务器的地址信息结构体给connect函数连接,
	//想连接哪个服务器,就填哪个服务器绑定的地址信息
	//真实的地址信息结构体根据地址族指定 AF_INET:man 7 ip
	struct sockaddr_in sin;
	sin.sin_family      = AF_INET;      //必须填AF_INET;
	sin.sin_port        = htons(PORT);  //服务器绑定的端口号
	sin.sin_addr.s_addr = inet_addr(IP);//服务器绑定的IP

	//连接指定服务器 connect
	if(connect(cfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
	{
		ERR_MSG("connect");
		return -1;
	}
	printf("connect success\n");


	//定义要监测的集合
	fd_set readfds,tempfds;

	FD_ZERO(&readfds);

	//将需要的文件描述符加入集合
	FD_SET(0,&readfds);
	FD_SET(cfd,&readfds);

	int s_res = -1;

	char buf[128] = "";
	ssize_t res = 0;

	while(1)
	{
		tempfds=readfds;
		s_res = select(cfd+1, &tempfds, NULL, NULL, NULL);
		if(s_res < 0)
		{
			ERR_MSG("selsct");	
			return -1;
		}
		else if(0 == s_res)
		{
			printf("time out....\n");
			break;
		}
		//运行到此,则代表集合中有文件描述符准备就绪

		if(FD_ISSET(0, &tempfds))
		{
			//清空字符串
			bzero(buf, sizeof(buf));    

			fgets(buf, sizeof(buf), stdin);
			buf[strlen(buf)-1] = 0;

			//发送
			if(send(cfd, buf, sizeof(buf), 0) < 0)
			{
				ERR_MSG("send");
				return -1;
			}
			printf("send success\n");
		}

		if(FD_ISSET(cfd, &tempfds))
		{
			bzero(buf, sizeof(buf));    //memset
			//接收
			res = recv(cfd, buf, sizeof(buf), 0);
			if(res < 0)
			{
				ERR_MSG("recv");
				return -1;
			}
			else if(0 == res)
			{
				printf("服务器下线 cfd=%d\n", cfd);
				break;
			}
			printf("cfd=%d : %s\n", cfd, buf);

		}
	}


	//关闭文件名描述符
	if(close(cfd) < 0)
	{
		ERR_MSG("close");
		return -1;
	}

	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

cloudCompare教程:一、可视化、点、线编辑

依据高度等准则(都在Scalar Fields中)渲染点云&#xff08;首先要打开Tools -> Projection -> Export coordinate to SF&#xff09; 在上述准则之外的&#xff0c;设置为不显示&#xff1a; 软件的显示设置&#xff08;首先打开右边的彩色柱状图&#xff0c;点击左边属性…

Qt::工程框架-工具栏停靠|悬浮-QDockWidget

二维矢量动画智能制作软件开发合集 链接&#xff1a;软件开发技术分享及记录合集 个人开发二维矢量动画智能制作软件界面如下&#xff1a; ​目录 一、界面停靠原理 二、界面停靠代码实现 三、界面停靠软件测试视频 结束语 一、工具栏停靠|悬浮原理 本软件的窗口设置如下…

2023年中国肠胃炎用药行业现状分析:随着老龄化进程明显加速,市场规模同比增长7%[图]

急性肠胃炎是一种因为饮食不当而引起的消化系统疾病&#xff0c;通常是因为摄入了含有病原菌的变质食物&#xff0c;或者过量食用刺激性食物&#xff0c;从而导致肠胃道黏膜发生急性炎症反应&#xff1b;慢性肠胃炎是一种长期存在症状并持续引发胃黏膜和肠黏膜发生慢性炎症反应…

超声雷达传感器与三角定位

1.概述 超声波雷达的工作原理是通过超声波发射装置向外发出超声波&#xff0c;到通过接收器接收到发送过来超声波时的时间差来测算距离。 对温度敏感性&#xff0c;使得超声波的速度具有如下特性 或 2.超声波雷达车位探测与障碍物检测 汽车超声波类装配方案多为前后向共8个UP…

28269-2012 座椅用蛇形弹簧 技术条件

声明 本文是学习GB-T 28269-2012 座椅用蛇形弹簧 技术条件. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了用圆截面材料制造的座椅用蛇形弹簧的技术要求、试验方法、检验规则及标志、包装、 运输、贮存。 本标准适用于车辆座椅…

APA技术架构与说明

1.自动泊车的硬件架构 2.APA自动泊车辅助系统 1&#xff09;APA主要包括以下典型功能 &#xff08;1&#xff09;泊车入库&#xff1a;利用超声波雷达或环视摄像头实现车位识别&#xff0c;并计算出合适行驶轨迹&#xff0c;对车辆进行横向/纵向控制使车辆驶入车位&#xff1…

20分钟---Vue2->Vue3

Vue官网地址&#xff1a;gVue.js - The Progressive JavaScript Framework | Vue.js 选项式vs组合式 vue的两种风格&#xff0c;搬运官网源码&#xff1a; 选项式 API (Options API)​ 使用选项式 API&#xff0c;我们可以用包含多个选项的对象来描述组件的逻辑&#xff0c…

28295-2012 高温合金管材通用技术条件

声明 本文是学习GB-T 28295-2012 高温合金管材通用技术条件. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 1.1 本标准规定了经过热、冷加工生产的变形高温合金管材产品交货的技术要求、试验方法、检验规则 和交货条件等技术内容。 1.2 本标…

Linux常用指令(二)

目录 一、 删除空目录&#xff08;rmdir&#xff09; 二、ln 硬链接与软链接 三、新建空文件或更新文件的时间戳&#xff08;touch&#xff09; 四、比较文件内容的差异&#xff08;diff&#xff09; 五、显示当前时间或设置系统时间&#xff08;date&#xff09; 六、显…

关于解决 unable to start ssh-agent service, error :1058

前言 操作系统&#xff1a;win11 命令终端&#xff1a;Powershell 当我在终端输入命令 启动 ssh-agent 代理的时候 ssh-agent -s 很不幸出现了 unable to start ssh-agent service, error :1058以下错误 问题的解决 查看我们ssh-agent 服务是否运行&#xff0c;执行如下命令…

自动驾驶技术:现状与未来

自动驾驶技术&#xff1a;现状与未来 文章目录 引言自动驾驶技术的现状自动驾驶技术的挑战自动驾驶技术的未来结论结论 2023星火培训【专项营】Apollo开发者社区布道师倾力打造&#xff0c;包含PnC、新感知等的全新专项课程上线了。理论与实践相结合&#xff0c;全新的PnC培训不…

代码随想录刷题 Day 22

235. 二叉搜索树的最近公共祖先 具体思路就是当小于pq的时候就往右取遍历&#xff0c;当大于的时候就往左遍历&#xff1b; lass Solution { public:TreeNode* traversal(TreeNode* current, TreeNode* p, TreeNode* q) {if (current->val > p->val && curre…

企业风险管理策略终极指南

企业风险管理不一定是可怕的。企业风险管理是一个模糊且难以定义的主题领域。它涵盖了企业的多种风险和程序&#xff0c;与传统的风险管理有很大不同。 那么&#xff0c;企业风险管理到底是什么&#xff1f;在本文中&#xff0c;我们将确定它是什么&#xff0c;提出两种常见的…

程序的编译与生成可执行文件学习笔记(二)

gcc不是编译器&#xff0c;它是一个程序 GCC&#xff08;GNU Compiler Collection&#xff09;是一款常用的编译器&#xff0c;它支持分段编译&#xff0c;可以将源代码分为预处理、编译、汇编和链接等不同的阶段进行处理。下面是GCC分段编译流程的命令示例&#xff1a; 1. 预…

【数据结构】外部排序、多路平衡归并与败者树、置换-选择排序(生成初始归并段)、最佳归并树算法

目录 1、外部排序 1.1 基本概念 1.2 方法 2、多路平衡归并与败者树 2.1 K路平衡归并 2.2 败者树 3、置换-选择排序&#xff08;生成初始归并段&#xff09;​编辑 4、最佳归并树 4.1 理论基础​编辑 4.2 构造方法 ​编辑 5、各种排序算法的性质 1、外部排序 1.1 基本概…

五分钟k8s入门到实战-应用配置

ConfigMap.png 背景 在前面三节中已经讲到如何将我们的应用部署到 k8s 集群并提供对外访问的能力&#xff0c;x现在可以满足基本的应用开发需求了。 现在我们需要更进一步&#xff0c;使用 k8s 提供的一些其他对象来标准化我的应用开发。首先就是 ConfigMap&#xff0c;从它的名…

高云FPGA系列教程(11):MultiButton按键驱动模块移植

文章目录 1. MultiButton简介2. MultiButton代码获取3. MultiButton移植4. 测试与运行本文是高云FPGA系列教程的第11篇文章。 1. MultiButton简介 MultiButton, 一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构…

华为云云耀云服务器L实例评测 | MacOS系统-宝塔建站

文章目录 1.华为云云耀云服务器L实例2.选择配置与购买2.1 华为云云耀云服务器L实例-套餐配置详情 3.宝塔镜像的使用3.1 重置实例的密码3.2 MacOS环境登录服务器3.2.1 查看内存使用情况 3.3 进入宝塔面板3.3.1 在安全组开放端口3.3.2 网站效果 1.华为云云耀云服务器L实例 云耀云…

python+pygame+opencv+gpt实现虚拟数字人直播(有趣的探索)

AI技术突飞猛进&#xff0c;不断的改变着人们的工作和生活。数字人直播作为新兴形式&#xff0c;必将成为未来趋势&#xff0c;具有巨大的、广阔的、惊人的市场前景。它将不断融合创新技术和跨界合作&#xff0c;提供更具个性化和多样化的互动体验&#xff0c;成为未来的一种趋…

SLAM从入门到精通(gmapping建图)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们介绍了hector slam建图。相对而言&#xff0c;hector slam建图对数据的要求比较低&#xff0c;只需要lidar数据就可以建图了。但是hector …