10.1select并发服务器以及客户端

news2024/11/30 2:45:58

服务器:

#include<myhead.h>

//do-while只是为了不让花括号单独存在,并不循环
#define ERR_MSG(msg) do{\
	fprintf(stderr,"%d:",__LINE__);\
	perror(msg);\
}while(0);

#define PORT 8888//端口号1024-49151
#define IP "192.168.2.54"//本机IP,终端输入ifconfig可得

int main(int argc, const char *argv[])
{
	//创建流式套接字 socket
	int sfd = socket(AF_INET,SOCK_STREAM,0);
	if(sfd<0){
		//printf("%d:",__LINE__);
		//perror("socket error");
		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;
	}
	printf("允许端口快速的被复用成功\n");

	//填充地址信息结构体给bind函数绑定
	//真是的地址信息结构体根据地址族制定 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
	//绑定服务器的地址信息  -->必须绑定    bind
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0){
		ERR_MSG("bind");
		return -1;
	}//指针类型的强转不会有数据丢失
	printf("bind success\n");

	//将套接字设置为被动监听状态 listen
	if(listen(sfd,128)<0){
		ERR_MSG("listen");
		return -1;
	}
	printf("listen success\n");

	//定义文件描述符集合
	fd_set readfds,tmpfds;

	//将文件描述符集合清空
	FD_ZERO(&readfds);
	//将文件描述符放入集合之中
	FD_SET(sfd,&readfds);
	FD_SET(0, &readfds);

	int maxfd = sfd;
	int res;
	char buf[128] = "";
	struct sockaddr_in cin;  //存储客户端的地址信息
	socklen_t addrlen = sizeof(cin);  //真实的地址信息结构体的大小
	//获取一个已经完成的客户端信息,生成一个新的文件描述符 accept
	int newfd;
	struct sockaddr_in saveCin[1024];  //备份连接成功的客户端的地址信息,用下标来对应地址信息 
	while(1){
		tmpfds = readfds;

		//调用select函数
		res = select(maxfd+1,&tmpfds, NULL, NULL, NULL);
		if(res < 0){
			ERR_MSG("select error");
			break;
		}else if(0 == res){
			printf("time out\n");
			break;
		}else{
			for(int i=0; i<=maxfd; i++){
				if(0==FD_ISSET(i, &tmpfds)){
					continue;
				}else if(-1==FD_ISSET(i, &tmpfds)){
					ERR_MSG("FD_ISSET error");
					break;
				}

				if(0==i){
					//终端输入
					printf("从终端读取成功::");
					fgets(buf,sizeof(buf),stdin);

					buf[strlen(buf)-1] = 0;

					printf("%s\n",buf);
				}
				else if(sfd == i){
					if((newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen))<0){
						ERR_MSG("accept");
						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, &readfds);

					//更新maxfd
					maxfd = maxfd>newfd?maxfd:newfd;


				}else{
					if(FD_ISSET(i, &readfds)){
						//清空字符串
						bzero(buf,sizeof(buf)); //memset

						//接收
						res = recv(i, 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[i].sin_addr),\
									ntohs(saveCin[i].sin_port),i);
							//将文件描述符从集合中踢出
							FD_CLR(i, &readfds);
							//由于踢出的文件描述符可能是最大文件描述符,更新maxfd
							/*		for(; maxfd>=0; maxfd--){
									if(FD_ISSET(maxfd, &readfds)){
									break;
									}
									}	*/

							while(FD_ISSET(maxfd, &readfds)==0 && maxfd-->=0);

							//关闭文件描述符
							close(i);
							continue;
						}
						printf("[%s:%d]客户端消息 newfd=%d:%s\n",\
								inet_ntoa(saveCin[i].sin_addr),\
								ntohs(saveCin[i].sin_port),i,buf);	


						//发送
						strcat(buf,">_<");
						if(send(i,buf,strlen(buf),0)<0){
							ERR_MSG("send");
							return -1;
						}
						printf("send success\n");			
					}				


				}
			}
/*
			//如果是终端输入就绪
			if(FD_ISSET(0,&tmpfds)){
				printf("从终端读取成功::");
				fgets(buf,sizeof(buf),stdin);

				buf[strlen(buf)-1] = 0;

				printf("%s\n",buf);
			}

			//如果是客户端连接就绪
			if(FD_ISSET(sfd,&tmpfds)){
				if((newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen))<0){
					ERR_MSG("accept");
					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, &readfds);

				//更新maxfd
				maxfd = maxfd>newfd?maxfd:newfd;
			}
			for(int i=4; i<=maxfd; i++){
				if(FD_ISSET(i, &readfds)){
					//清空字符串
					bzero(buf,sizeof(buf)); //memset

					//接收
					res = recv(i, 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[i].sin_addr),\
								ntohs(saveCin[i].sin_port),i);
						//将文件描述符从集合中踢出
						FD_CLR(i, &readfds);
						//由于踢出的文件描述符可能是最大文件描述符,更新maxfd
						for(; maxfd>=0; maxfd--){
							if(FD_ISSET(maxfd, &readfds)){
								break;
							}
						}	

						while(FD_ISSET(maxfd, &readfds)==0 && maxfd-->=0);

						//关闭文件描述符
						close(i);
						continue;
					}
					printf("[%s:%d]客户端消息 newfd=%d:%s\n",\
							inet_ntoa(saveCin[i].sin_addr),\
							ntohs(saveCin[i].sin_port),i,buf);	


					//发送
					strcat(buf,">_<");
					if(send(i,buf,strlen(buf),0)<0){
						ERR_MSG("send");
						return -1;
					}
					printf("send success\n");			
				}
			}*/
		}
	}


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


	return 0;
}

服务器:

#include<myhead.h>

//do-while只是为了不让花括号单独存在,并不循环
#define ERR_MSG(msg) do{\
	fprintf(stderr,"%d:",__LINE__);\
	perror(msg);\
}while(0);

#define PORT 8888//端口号1024-49151
#define IP "192.168.2.54"//本机IP,终端输入ifconfig可得

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

	//填充服务器的地址信息结构体给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
	socklen_t addrlen    = sizeof(sin);
	//连接指定服务器 connect
	if(connect(cfd,(struct sockaddr*)&sin,addrlen)<0){
		ERR_MSG("connect");
		return -1;
	}

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

	//定义文件描述符集合
	fd_set readfds,tmpfds;
	//初始化集合
	FD_ZERO(&readfds);
	//把cfd加入集合
	FD_SET(cfd, &readfds);
	//把标准输入加入集合
	FD_SET(0, &readfds);
	int ret = -1;
	while(1){
		tmpfds = readfds;
		ret = select(cfd+1, &tmpfds, NULL, NULL, NULL);

		if(ret<0){
			ERR_MSG("select error");
			break;
		}else if(0 == ret){
			printf("time out\n");
			break;
		}else{
			if(FD_ISSET(0, &tmpfds)){
				//说明有来自终端的输入,需要发送
				//清空字符串
				bzero(buf,sizeof(buf)); //memset
				printf("请输入>> ");
				fgets(buf,sizeof(buf),stdin);
				buf[strlen(buf)-1] = 0;

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

			if(FD_ISSET(cfd, &tmpfds)){
				//套接字文件的接收缓冲区有数据,需要接收
				//说明有来自终端的输入,需要发送
				//清空字符串
				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("[%s:%d]服务器下线 cfd=%d\n",\
							inet_ntoa(sin.sin_addr),\
							ntohs(sin.sin_port),cfd);
					break;
				}
				printf("[%s:%d]服务器消息 cfd=%d:%s\n",\
						inet_ntoa(sin.sin_addr),\
						ntohs(sin.sin_port),cfd,buf);
			}

		}

	
	}


/*
	while(1){
		//清空字符串
		bzero(buf,sizeof(buf)); //memset
		printf("请输入>> ");
		fgets(buf,sizeof(buf),stdin);
		buf[strlen(buf)-1] = 0;

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

		//接收
		res = recv(cfd, buf, sizeof(buf) ,0);
		if(res<0){
			ERR_MSG("recv");
			return -1;
		}else if(0==res){
			printf("[%s:%d]服务器下线 cfd=%d\n",\
					inet_ntoa(sin.sin_addr),\
					ntohs(sin.sin_port),cfd);
			break;
		}
		printf("[%s:%d]服务器消息 cfd=%d:%s\n",\
					inet_ntoa(sin.sin_addr),\
					ntohs(sin.sin_port),cfd,buf);		
	}
*/
	//关闭文件描述符
	//close(newfd);
	if(close(cfd)<0){
		ERR_MSG("close");
		return -1;
	}


	return 0;
}

效果:

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

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

相关文章

10月1日作业

汇编指令合集 用select实现服务器并发代码 #include<myhead.h> #define IP "192.168.0.106" #define PORT 8888int main(int argc, const char *argv[]) {//新建套接字文件int sfd socket(AF_INET, SOCK_STREAM, 0);if(sfd < 0){ERR_MSG("socket&quo…

imgui开发笔记<4>、image-slider online

在线滑条二值化。 // // Created by sry on 2021/6/30. //#include"imgui.h" #include "imgui_impl_glfw.h" #include "imgui_impl_opengl3.h" #include <stdio.h> // Initialize with gl3wInit() #include<GL/gl3w.h> // Include …

【MATLAB第78期】基于MATLAB的VMD-SSA-LSTM麻雀算法优化LSTM时间序列预测模型

【MATLAB第78期】基于MATLAB的VMD-SSA-LSTM麻雀算法优化LSTM时间序列预测模型 一、LSTM data xlsread(数据集.xlsx);% [x,y]data_process(data,15);%前15个时刻 预测下一个时刻 %归一化 [xs,mappingx]mapminmax(x,0,1);xxs; [ys,mappingy]mapminmax(y,0,1);yys; %划分数据 n…

Android进阶——Handler底层fd监听之epoll机制

文章大纲 引言一、从网卡接收数据说起二、如何知道接收了数据&#xff1f;三、进程阻塞为什么不占用cpu资源&#xff1f;四、那么阻塞的原理是什么&#xff1f;1、工作队列2、等待队列3、唤醒进程 五、内核接收网络数据全过程六、同时监视多个socket的简单方法七、epoll的设计思…

Redis入门到精通——00数据类型

1、String 1.1、介绍 String 是最基本的 key-value 结构&#xff0c;key 是唯一标识&#xff0c;value 是具体的值&#xff0c;value其实不仅是字符串&#xff0c; 也可以是数字&#xff08;整数或浮点数&#xff09;&#xff0c;value 最多可以容纳的数据长度是 512M 1.2、…

聊天、会议、多媒体一体化:多平台支持的即时通讯系统 | 开源日报 No.44

harness/gitness Stars: 28.2k License: Apache-2.0 Gitness 是一个建立在 Drone 之上的新型开源开发者平台&#xff0c;具备代码托管和流水线功能。它提供了以下核心优势&#xff1a; 轻量级、超快速的代码托管和持续集成服务支持 Docker 容器化部署可以在本地环境中构建和…

【C/C++笔试练习】二维数组、二维数组的访问,解引用,地址计算、计算糖果、进制转换

文章目录 C/C笔试练习1.二维数组&#xff08;1&#xff09;二维数组的访问&#xff08;2&#xff09;二维数组的初始化&#xff08;3&#xff09;二维数组的解引用&#xff08;4&#xff09;二维数组的解引用&#xff08;5&#xff09;多维数组的解引用&#xff08;6&#xff0…

没有社会性的人机环境系统智能是危险的

缺乏社会性的人工智能常常存在着一定的潜在危险性&#xff0c;这是因为&#xff1a; 首先&#xff0c;社会性对于人类而言是非常重要的&#xff0c;我们通过社交互动、合作和沟通来建立联系、理解他人以及共同解决问题。人类具有复杂的情感和道德价值观&#xff0c;这些因素在我…

嵌入式学习笔记(39)蜂鸣器和PWM定时器编程实践

7.4.1蜂鸣器的工作原理 (1)蜂鸣器里边有2个金属片&#xff0c;离得很近但没挨着。没电的时候两个金属片在弹簧本身的张力作用下分开彼此平行&#xff0c;有电的时候两边分别充电&#xff0c;在异性电荷的吸力作用下两个片挨着。 (2)我们只要以快速的频率给蜂鸣器的正负极供电…

redis使用学习笔记

文章目录 关于redis的简单性能概括Redis命令行客户端Redis命令Redis通用命令String类型key的层级格式Hash类型List类型Set类型SortedSet类型 Redis的Java客户端Jedis使用基本步骤Jedis连接池 SpringDataRedisRedisTemplate快速入门RedisSerializer 关于redis的简单性能概括 键…

c语言练习72:关于截断和整形提升

关于截断和整形提升 思考: 什么时候会发生截断和整形提升? 当以int的形式定义一个变量然后以char的形式输出是就会发生截断和整形提升 例如: #include<stdio.h> int main() {char c1, c2, c3;int i, j;c1 a, c2 97, c3 243;i b, j 1 c1;printf("%c %d\n…

Airtool for Mac——高效便捷的系统菜单栏网络工具!

在我们的数字化生活中&#xff0c;对于网络连接的稳定性和速度有着越来越高的需求。为了满足您对网络质量的实时监测和分析的需求&#xff0c;我们向大家介绍一款强大的Mac系统菜单栏网络工具——Airtool&#xff01; Airtool是一款专为Mac设计的网络工具&#xff0c;它能够提…

每日一练-Q2-贝博士的机械零件-20231001

目录 1.题目描述 2.输入描述 3.示例提示 4.问题分析 5.通过代码 1.题目描述 贝博士是个大忙人&#xff0c;他在设计和制造一台非常复杂的机械式计算机。 最近贝博士有一点烦恼&#xff0c;因为机械零件的种类繁多&#xff0c;磨损又快&#xff0c;经费不太够用了。不过&…

【C++】string 之 substr、insert、erase函数的学习

前言 之前两篇文章 我们学习了 assign、at、append函数 find、rfind、replace、compare函数 这些函数。接下来让我们继续学习其他函数 substr 两个参数 pos1&#xff0c;截取的开始位置 len&#xff0c;截取的子串长度 作用是在字符串中截取一段长度为len的子串 下面给出…

最新整理源码面试题

经典框架源码面试题 Lecture&#xff1a;波哥 1.谈谈你对框架的理解 1.1 框架的作用 JavaWeb中的框架是一种开发工具或者平台&#xff0c;它提供了一系列的功能和组件&#xff0c;用于简化和加速Web应用的开发过程。框架可以提供一些基础设施&#xff0c;如数据库访问、用户认…

Linux系统之部署Linux命令大全搜索工具

Linux系统之部署Linux命令大全搜索工具 一、linux-command介绍二、本次实践介绍2.1 本地环境规划2.2 本次实践介绍 三、安装httpd软件3.1 检查yum仓库3.2 安装httpd软件3.3 启动httpd服务3.4 查看httpd服务状态3.5 防火墙和selinux设置3.6 浏览器测试web服务 四、安装linux-com…

【AI视野·今日CV 计算机视觉论文速览 第255期】Wed, 27 Sep 2023

AI视野今日CS.CV 计算机视觉论文速览 Wed, 27 Sep 2023 (showing first 100 of 103 entries) Totally 100 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers Generating Visual Scenes from Touch Authors Fengyu Yang, Jiacheng Zhang, Andre…

螺丝帽验证码

网址&#xff1a;https://captcha.luosimao.com/demo 啥价螺丝帽验证码&#xff1f;&#xff1f;&#xff1f;一开始我也不知道&#xff0c;看k哥发了个动态就学了一下。 个人总结&#xff1a;难点在图片还原。 要或者图片的坐标的话&#xff0c;最简单快速的方式&#xff1a…

Spring的注解开发-注解原理解析-xml方式/注解方式组件扫描

目录 Spring注解的解析原理 xml配置组件扫描 注解方式配置组件扫描 原理图 yysy&#xff0c;没有搞太明白&#xff0c;真的复杂&#xff0c;欢迎大佬留言解惑 Spring注解的解析原理 使用Component等注解配置完毕后&#xff0c;要配置组件扫描才能使注解生效 xml配置组件扫…

尚硅谷HTML习笔记

计算机的两位先驱&#xff1a; 1、图灵 人工智能之父 2、冯诺依曼 现代计算机之父 计算机的组成 一、软件&#xff1a;分为系统软件和应用软件 系统软件&#xff1a;windows、mac、linux、harmony 应用软件&#xff1a;下载的软件如微信 二、硬件&#xff1a; ①中央处理器&am…