国庆10.1

news2024/11/30 12:52:56

用select实现服务器并发

ser

#include <myhead.h>	

#define ERR_MSG(msg)  do{\
	fprintf(stderr, "__%d__", __LINE__);\
	perror(msg);\
}while(0)

#define PORT 8888      //端口号,范围1024~49151
#define IP   "192.168.1.205"    //本机IP,ifconfig    

int main(int argc, const char *argv[])
{
	//创建流式套接字 socket
	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;
	}
	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, 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] = "";

	int newfd = -1;
	struct sockaddr_in cin; 			//存储客户端的地址信息
	socklen_t addrlen = sizeof(cin); 	//真实的地址信息结构体大小

	while(1)
	{
		tempfds = readfds;

		//执行IO多路复用函数
		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;
		}
		printf("__%d__", __LINE__);

		//判断是否是0号
		if(FD_ISSET(0, &tempfds))
		{
			printf("触发键盘输入事件\n");

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

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

		//判断是否是sfd
		if(FD_ISSET(sfd, &tempfds))
		{
			printf("触发客户端连接事件\n");
			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);

			FD_SET(newfd, &readfds);      //将newfd添加到集合中

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

		//除了0和sfd事件外,其余均为newfd对应的客户端交互事件
		//通过循环i(i是文件描述符),遍历所有newfd是否在tempfds中
		for(int i=4; i<=maxfd; i++)
		{
			if(FD_ISSET(i, &tempfds))
			{
				printf("触发客户端交互事件\n");
				//清空字符串
				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(cin.sin_addr), ntohs(cin.sin_port), i);

					//关闭文件描述符
					close(i);
					//将文件描述符从集合中剔除
					FD_CLR(i, &readfds);

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

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

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

	return 0;
}

cli

#include <myhead.h>	

#define ERR_MSG(msg)  do{\
	fprintf(stderr, "__%d__", __LINE__);\
	perror(msg);\
}while(0)

#define PORT 8888      //端口号,范围1024~49151
#define IP   "192.168.1.205"    //本机IP,ifconfig    

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


	//填充地址信息结构体给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

	
	//连接指定服务器 connect
	if(connect(cfd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
	{
		ERR_MSG("connect");
		return -1;
	}
	printf("connect success\n");
	
	//定义要检测的集合
	struct pollfd fds[2];
	memset(fds, 0, sizeof(fds));

	//将需要的文件描述符添加到集合中
	fds[0].fd = 0;      //指定监测0号文件描述符
	fds[0].events = POLLIN; 	//指定监测读事件

	fds[1].fd = cfd;
	fds[1].events = POLLIN;

	int nfds = 2;
	int p_res = -1;

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

	while(1)
	{
		p_res = poll(fds, nfds, -1);
		if(p_res < 0)
		{
			ERR_MSG("poll");
			return -1;
		}else if(0 == p_res)
		{
			printf("time out...\n");
			break;
		}

		//能运行到当前位置,则代表集合中有文件描述符准备就绪了		
		通过按位与的方式提取revents中代表POLLIN的哪一个bit
		if((fds[0].revents & POLLIN) != 0)
		{
			printf("触发键盘输入事件\n");

			//清空字符串
			bzero(buf, sizeof(buf));  //也可以用memset
			printf("请输入>>> ");
			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(fds[1].revents & POLLIN)
		{
			printf("触发服务器交互事件\n");
			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/1054845.html

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

相关文章

ARMv7-A 那些事 - 5.CP15协处理器

By: Ailson Jack Date: 2023.10.01 个人博客&#xff1a;http://www.only2fire.com/ 本文在我博客的地址是&#xff1a;http://www.only2fire.com/archives/157.html&#xff0c;排版更好&#xff0c;便于学习&#xff0c;也可以去我博客逛逛&#xff0c;兴许有你想要的内容呢。…

14:STM32-----看门狗

目录 一:看门狗 1:WDG 2:独立看门狗 (IWDG) A:IWDG框图 B:IWDG_KR键寄存器 C:IWDG超时时间 3:窗口看门狗 (WWDG) A:WWDG框图 B:WWDG工作特性 C:WWDG超时时间 4:独立看门狗和窗口看门狗的区别 5:数据手册 二:案例 A:独立看门狗 1:连接图 2:步骤 3:函数介绍 3:代…

网络爬虫——urllib(2)

前言&#x1f36d; ❤️❤️❤️网络爬虫专栏更新中&#xff0c;各位大佬觉得写得不错&#xff0c;支持一下&#xff0c;感谢了&#xff01;❤️❤️❤️ Python网络爬虫_热爱编程的林兮的博客-CSDN博客 前篇讲解了urllib的基本使用、一个类型六个方法与下载相关内容&#xff0…

《深入浅出OCR》第二章:OCR技术发展与分类

✨专栏介绍: 经过几个月的精心筹备,本作者推出全新系列《深入浅出OCR》专栏,对标最全OCR教程,具体章节如导图所示,将分别从OCR技术发展、方向、概念、算法、论文、数据集等各种角度展开详细介绍。 👨‍💻面向对象: 本篇前言知识主要介绍深度学习知识,全面总结知知识…

Python3数据科学包系列(一):数据分析实战

Python3中类的高级语法及实战 Python3(基础|高级)语法实战(|多线程|多进程|线程池|进程池技术)|多线程安全问题解决方案 Python3数据科学包系列(一):数据分析实战 Python3数据科学包系列(二):数据分析实战 认识下数据科学中数据处理基础包: (1)NumPy 俗话说: 要学会跑需先…

C++核心编程--多态篇

4.7、多态 4.7.1、多态的基本概念 多态是C面向对象三大特征之一 多态分为两类 静态多态&#xff1a;函数重载和运算符重载属于静态多态&#xff0c;复用函数名动态多态&#xff1a;派生类和虚函数实现运行时多态 静态多态和动态多态区别&#xff1a; 静态多态的函数地址早…

Eclipse 主网即将上线迎空投预期,Zepoch 节点或成受益者?

目前&#xff0c;Zepoch 节点空投页面中&#xff0c;模块化 Layer2 Rollup 项目 Eclipse 出现在其空投列表中。 配合近期 Eclipse 宣布了其将由 SVM 提供支持的 Layer2 主网架构&#xff0c;并将在今年年底上线主网的消息后&#xff0c;不免引发两点猜测&#xff1a;一个是 Ecl…

springcloud:四、nacos介绍+启动+服务分级存储模型/集群+NacosRule负载均衡

nacos介绍 nacos是阿里巴巴提供的SpringCloud的一个组件&#xff0c;算是eureka的替代品。 nacos启动 安装过程这里不再赘述&#xff0c;相关安装或启动的问题可以见我的另一篇博客&#xff1a; http://t.csdn.cn/tcQ76 单价模式启动命令&#xff1a;进入bin目录&#xff0…

某房产网站登录RSA加密分析

文章目录 1. 写在前面2. 抓包分析3. 扣加密代码4. 还原加密 1. 写在前面 今天是国庆节&#xff0c;首先祝福看到这篇文章的每一个人节日快乐&#xff01;假期会老的这些天一直在忙事情跟日常带娃&#xff0c;抽不出一点时间来写东西。夜深了、娃也睡了。最近湖南开始降温了&…

SimpleCG动画示例--汉诺塔动画演示

前言 SimpleCG的使用方法在前面已经介绍了许多&#xff0c;有兴趣的同学如果有去动手&#xff0c;制作一些简单动画应该没多大问题的。所以这次我们来演示一下简单动画。我们刚学习C语言的递归函数时&#xff0c;有一个经典例子相信很多同学都写过&#xff0c;那就是汉诺塔。那…

【算法优选】双指针专题——壹

文章目录 &#x1f60e;前言&#x1f334;[移动零](https://leetcode.cn/problems/move-zeroes/)&#x1f6a9;题⽬描述&#xff1a;&#x1f6a9;算法思路&#x1f6a9;算法流程&#x1f6a9;代码实现 &#x1f340;[复写零](https://leetcode.cn/problems/duplicate-zeros/)&…

深入浅出线程池

一、线程 1、什么是线程 线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中&#xff0c;是进程中的实际 运作单位。一条线程指的是进程中一个单一顺序的控制流&#xff0c;一个进程中可以并发多个线程&#xff0c;每条线 程并行执行不同的任务。 2、如…

2023-10-01 LeetCode每日一题(买卖股票的最佳时机)

2023-10-01每日一题 一、题目编号 121. 买卖股票的最佳时机二、题目链接 点击跳转到题目位置 三、题目描述 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一…

Python Appium 安卓自动化测试 基本使用 - Phone Spider

Python Appium 安卓自动化测试 基本使用 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 文章目录 Python Appium 安卓自动化测试 基本使用前言一、环境安装1.1 Python Pip…

【接口技术】输入输出接口习题

1&#xff1a;图1所示电路PC/XT系统板上的接口控制电路的端口地址译码电路。写出8237A&#xff0c;8259A&#xff0c;8253&#xff0c;8255A的端口地址范围 解答&#xff1a; 【G1A非】和【G2B非】为低电平有效&#xff0c;因此A80&#xff0c;A90 74ls138中&#xff0c;是按…

python代码混淆与代码打包

0x00 背景 自己写的项目&#xff0c;又想保护源码&#xff0c;自己做个混淆是最方便的了。 0x01 实践 这里使用开源工具 GitHub - astrand/pyobfuscate: pyobfuscate&#xff0c;虽然git上才500多star&#xff0c;但是很好用。它的使用场景是混淆单个py文件。很多事物有开始就…

六、vpp 流表

草稿&#xff01;&#xff01;&#xff01; vpp node其实就是三个部分 1、plugin init 2、set command 3、function 实现功能&#xff0c;比如这里的流表 这里的function函数有个返回值&#xff0c;根据返回值决定下一个节点走哪里 flowtable_getinfo这里处理函数返回2 &#…

Nodejs沙箱逃逸

一、基本概念 JavaScript和Nodejs之间有什么区别 JavaScript用在浏览器前端&#xff0c;后来将Chrome中的v8引擎单独拿出来为JavaScript单独开发了一个运行环境&#xff0c;因此JavaScript也可以作为一门后端语言&#xff0c;写在后端&#xff08;服务端&#xff09;的JavaScr…

什么是博弈论?

什么是博弈&#xff1f;字面描述中&#xff0c;博弈由两个字构成&#xff1a;博 和 弈。博弈是一种双方&#xff08;多方&#xff09;的对抗&#xff08;比赛&#xff09;&#xff0c;对抗总是在一定的规则下进行&#xff0c;参与者必然会考虑应用相应的策略&#xff08;计谋&a…

防火墙基础之H3C防火墙分支与分支之间双向地址转换

分支与分支之间双向地址转换 原理概述&#xff1a; 防火墙&#xff08;英语&#xff1a;Firewall&#xff09;技术是通过有机结合各类用于安全管理​与筛选的软件和硬件​设备&#xff0c;帮助计算机网络于其内、外网之间构建一道相对隔绝的保护屏障&#xff0c;以保护用户资…