使用select实现TCP并发服务器模型

news2024/11/25 4:39:19

文章目录

  • 前言
  • 一、select是什么?
    • 1.1 高级IO模型
    • 1.2 select实现
    • 1.3 select缺点:
  • 二、使用select实现TCP并发服务器模型
    • 1.引入库
    • 2.TCP服务器端
    • 3. TCP服务器端
    • 3. 运行结果
  • 总结


前言

本期主要分享的是对于select的使用,使用select实现TCP并发服务器模型,由于之前所用到的技术知识只能够支撑我们进行单个访问,但是有了select之后呢,我们就能够实现多用户进行访问;这也是非常符合客观需求的;


一、select是什么?

1.1 高级IO模型

(1)阻塞IO
	效率高,等待数据过程中不占用CPU资源	
(2)非阻塞IO
    能够解决多个文件描述符来数据的情况
	效率低,等待数据过程中CPU不断轮询所有文件描述符是否有数据	  
(3)异步IO
   当监听文件描述符有数据时,发送信号,收到信号接收数据
   只能应用在文件描述符比较少的情况下	
(4)多路复用IO
   select	   
   poll	   
   epoll

这次呢我们重点来使用一下select;

1.2 select实现

1.函数接口
	(1)select 
	   int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
	   功能:
			监听文件描述符集合
	   参数:
			nfds:最大文件描述符个数+1
			readfds:读文件描述符集合
			writefds:写文件描述符集合
			exceptfds:其余文件描述符集合
			timeout:设定超时时间
			NULL:永远等待,直到有数据发生
	   返回值:
			成功返回产生事件的文件描述符个数
			失败返回-1 	
2. void FD_CLR(int fd, fd_set *set);
	功能:将fd从文件描述符集合中移除		
	
3. int  FD_ISSET(int fd, fd_set *set);
	功能:判断fd是否仍在文件描述符集合中		
	
4. void FD_SET(int fd, fd_set *set);
	功能:将fd加入文件描述符集合			
	
5. void FD_ZERO(fd_set *set);
	功能:将文件描述符集合清0 

1.3 select缺点:

(1)select监听文件描述符个数上限为1024
(2)select监听的文件描述符集合在应用层,事件发时,内核数据需要传递给应用层,造成资源开销
(3)select需要手动检测产生事件的文件描述符
(4)select只能工作在水平触发模式(低速模式)

二、使用select实现TCP并发服务器模型

1.引入库

用到的头文件如下:

#ifndef __HEAD_H__
#define __HEAD_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>

#endif

2.TCP服务器端

我在前面不做过多的文字陈述,大家看代码的时候一定得看注释(非常详细),认真分析,代码如下(示例):

#include "head.h"

int main(int argc, const char *argv[])
{
	int sockfd = 0;
	struct sockaddr_in recvaddr;
	int ret = 0;
	fd_set readfds;
	fd_set tmpfds;
	int maxfd;
	int i = 0;
	int confd = 0;
	char tmpbuff[1024] = {0};
	ssize_t nsize = 0;
	int nready = 0;

	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sockfd)
	{
		perror("fail to socket");
		return -1;
	}

	recvaddr.sin_family = AF_INET;
	recvaddr.sin_port = htons(50000);
	recvaddr.sin_addr.s_addr = inet_addr("192.168.209.128");

	ret = bind(sockfd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
	if (-1 == ret)
	{
		perror("fail to bind");
		return -1;
	}

	ret = listen(sockfd, 10);
	if (-1 == ret)
	{
		perror("fail to listen");
		return -1;
	}

	FD_ZERO(&readfds);			//清空文件描述符集合
	FD_SET(sockfd, &readfds);	//将sockfd加入到文件描述符集合中
	maxfd = sockfd;				//此时sockfd就是最大的文件描述符

	while (1)
	{
		tmpfds = readfds;		//每次循环最开始必须是所有目前已经加入的所有文件描述符
		nready = select(maxfd+1, &tmpfds, NULL, NULL, NULL);	//进行事件监听
		if (-1 == nready)
		{
			perror("fail to select");
			return -1;
		}

		if (FD_ISSET(sockfd, &tmpfds))		//判断是否有tcp通信文件描述符
		{
			confd = accept(sockfd, NULL, NULL);		//进行三次握手链接
			if (-1 == confd)						
			{
				perror("fail to accept");
				close(sockfd);						
				FD_CLR(sockfd, &readfds);
				break;								//出错后直接退出,因为sockfd只有一个,是server通信的文件描述符,而confd是不同的客户端请求就会对应产生一个
			}
			FD_SET(confd, &readfds);
			maxfd = maxfd > confd ? maxfd : confd;		//防止0,1,2三个文件描述符在前面关闭,confd去替补了,所以这里使用三目运算符对confd和maxfd进行判断
		}

		for (i = sockfd + 1; i <= maxfd;++i)		//只判断confd的事件,也就是客户端的事件(客户端用的是confd通信)
		{
			if (FD_ISSET(i, &tmpfds))
			{
				memset(tmpbuff, 0, sizeof(tmpbuff));
				nsize = recv(i, tmpbuff, sizeof(tmpbuff), 0);	//接收客户端消息
				if (-1 == nsize)
				{
					perror("fail to recv");
					close(i);
					FD_CLR(i, &readfds);
					continue;		//继续判断下一个
				}
				else if (0 == nsize)
				{
					close(i);
					FD_CLR(i, &readfds);
					continue;		//继续判断下一个
				}
				printf("recv = %s\n", tmpbuff);						//打印来自于客户端的消息
				sprintf(tmpbuff, "%s----recv", tmpbuff);			//回复消息
				nsize = send(i, tmpbuff, strlen(tmpbuff), 0);
				if (-1 == nsize)
				{
					perror("fail to send");
					close(i);
					FD_CLR(i, &readfds);
					continue;										//发送完毕后继续轮询看别的客户端是否有事件发生
				}
			}
		}
	}

	close(confd);
	close(sockfd);

	return 0;
}

3. TCP服务器端

服务器端比较简单,就是发送消息给服务器等待解接收回复,select主要还是体现在server端;

#include "head.h"

int main(int argc, const char *argv[])
{
	int sockfd = 0;
	struct sockaddr_in senaddr;
	char tmpbuff[1024] = {0};
	int count = 0;
	ssize_t nsize = 0;
	int ret = 0;

	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sockfd)
	{
		perror("fail to spckfd");
		return -1;
	}

	senaddr.sin_family = AF_INET;
	senaddr.sin_port = htons(50000);
	senaddr.sin_addr.s_addr = inet_addr("192.168.209.128");

	ret = connect(sockfd, (struct sockaddr *)&senaddr, sizeof(senaddr));
	if (-1 == ret)
	{
		perror("fail to connect");
		return -1;
	}

	while (1)
	{
		memset(tmpbuff, 0, sizeof(tmpbuff));
		sprintf(tmpbuff, "hello ------->%d", count);
		count++;
		nsize = send(sockfd, tmpbuff, strlen(tmpbuff), 0);		//发送给服务器
		if (-1 == nsize)
		{
			perror("fail to send");
			return -1;
		}

		memset(tmpbuff, 0, sizeof(tmpbuff));
		nsize = recv(sockfd, tmpbuff, sizeof(tmpbuff), 0);
		if (nsize <= 0)
		{
			break;
		}
		printf("%s\n", tmpbuff);
	}

	close(sockfd);
	return 0;
}

3. 运行结果

最后,我们来看一下运行结果:
在这里插入图片描述


总结

本期分享的这个模型确实能够实现我们这个多任务并发,每当客户端有消息发来时,select监听到才会向下执行,这是它的优点;希望各位小伙伴一定手动练习起来哦!
最后,各位小伙伴们如果喜欢我的分享可以点赞收藏哦,你们的认可是我创作的动力,一起加油!

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

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

相关文章

JSR-133/Java内存模型(JMM)规范

by Doug Lea, with help from members of the JMM mailing list. 原文地址 The JSR-133 Cookbook for Compiler Writers 重排序(Reorderings)Volatiles and MonitorsFinal Fields 内存屏障(Memory Barrires)屏障类别数据依赖和屏障之间的关系原子指令与屏障之间的相互作用 屏…

总结885

5月小结 数学做了1800基础部分&#xff0c; 英语背了7篇文章 每日必复习&#xff08;5分钟&#xff09; 画思维导图1~15讲 学习内容&#xff1a; 英语&#xff1a;继续 背诵《we stand on the same starting point》 数学&#xff1a;进步本题目&#xff0c;我知道为啥总会…

嵌入式调试技巧-代码自动初始化

代码自动初始化 概述 在嵌入式开发过程中&#xff0c;可能会遇到初始化代码自动初始化&#xff0c;比如RTT中就运用到这项技术。那么初始化代码是如何做到自动化调用的呢&#xff1f; 在嵌入式实际开发过程中&#xff0c;往往需要对 bsp 部分进行外设配置&#xff0c;以及一…

springboot+vue+java在线考试系统 试题库组卷系统

这次开发的精品在线试题库系统有管理员&#xff0c;教师&#xff0c;学生三个角色。管理员功能有个人中心&#xff0c;专业管理&#xff0c;学生管理&#xff0c;教师管理&#xff0c;试卷管理&#xff0c;试题管理&#xff0c;考试管理。教师可以管理试题和试卷&#xff0c;查…

基于C#制作一个贪吃蛇小游戏

基于C#制作一个贪吃蛇小游戏,简单耐玩,操作简单。 一、项目创建1.1、创建1.2、素材准备1.3、界面绘制1.4、设置定时器1.5、获取键盘事件1.6、游戏结束事件二、帮助类2.1、坐标DTO2.2、果实DTO2.3、移动DTO结语一、项目创建 1.1、创建 打开Visual Studio,右侧选择创建新项目…

AutoGPT 使用教程及上手体验(一分钟配置可用)

ChatGPT 是新一代 AI 文本助手&#xff0c;可以帮助解决我们在多个领域的问题。 在某些复杂问题上&#xff0c;ChatGPT 需要经过不断的调教与沟通&#xff0c;才能得到接近正确的答案。 当你是某个领域的专家时&#xff0c;你很容易做到这一点。 但是&#xff0c;在你不熟悉…

【Linux】文件的压缩和解压

欢迎来到博主 Apeiron 的博客&#xff0c;祝您旅程愉快 &#xff01; 时止则止&#xff0c;时行则行。动静不失其时&#xff0c;其道光明。 目录 1、压缩格式 2、压缩软件 3、tar 命令简介 4、tar 命令压缩 5、总结 1、压缩格式 在市面上有非常多的压缩格式&#xff0c;…

蓝牙技术|苹果Apple Watch新专利,可监测用户更多健康指标

根据美国商标和专利局&#xff08;USPTO&#xff09;近日公示的清单&#xff0c;苹果获得了一项 Apple Watch 相关的专利&#xff0c;可以在表带嵌入 NFC、RFID 和蓝牙等组件&#xff0c;从而实现某些特定功能。 在苹果的构想中&#xff0c;未来的 Apple Watch 可以“识别”表…

BR 5AP920.1505-01 模拟电阻式触摸屏

材料编号: 5AP920.1505-01 描述: 15英寸XGA彩色TFT显示屏模拟电阻式触摸屏安装深度小无风扇运行可以用显示链接卡或PPC300升级 自动化面板AP920&#xff0c;15英寸XGA彩色TFT显示屏&#xff0c;带触摸屏(电阻式)&#xff0c;3个USB 2.0接口&#xff0c;用于自动化面板链接的…

万方 protobuf 反序列化

protobuf 是一种轻便高效的结构化数据存储格式&#xff0c;可以用于结构化数据串行化&#xff0c;或者说序列化。 在网络传输方面&#xff0c;相比传统的json&#xff0c;有着更快、更小&#xff0c;且加密性好的特点。 在实际应用中&#xff0c;万方数据库官网发送的请求&…

03 【数据代理 事件处理】

03 【数据代理 事件处理】 1.数据代理 了解数据代理需要js的一些知识&#xff1a;Object.defineProperty()&#xff0c;属性标志&#xff0c;属性描述符&#xff0c;getter&#xff0c;setter。。。 1.1数据代理 建议学习文章地址&#xff1a; https://zh.javascript.info/p…

MathType7.4永久中文Mac+Win全平台版本

MathType7.4版是一款功能强大、专业实用、应用范围广的数学公式编辑器软件&#xff0c;这款软件采用了简体中文操作界面并且完美兼容office、wps等一系列常见办公工具&#xff0c;这样就能够很好的为相关用户省去了许多繁琐的操作步骤&#xff0c;用户在这里可以轻轻松松进行公…

最小编译器和 UI 框架「GitHub 热点速览」

作者&#xff1a;HelloGitHub-小鱼干 如果有一个关键词来概述本周的 GitHub 热门项目的话&#xff0c;大概就是 van 和 sectorc 都用到的 smallest。只不过一个是前端的响应式框架&#xff0c;一个是搞编译的 C 编译器。它们除了轻量化这个共同特点之外&#xff0c;还有好用&am…

解决无法ssh命令登录wsl问题

本地主机ssh登录wsl报错被拒绝访问 C:\Users\jiangcheng> ssh rootxxx.xx.xxx.xx -p 22 ssh: connect to host xxx.xx.xxx.xx port 22: Connection refused 解决步骤如下&#xff1a; 1&#xff0c;解决密码不对的问题 wsl默认用户名root的密码是随机的&#xff0c;需要…

【深度学习】yolov7 pytorch模型转onnx,转ncnn模型和mnn模型使用细节

文章目录 前言1.前置1.1 安装必要的库1.2 .pt 权重转ncnn 和mnn所需要的权重 2、编码C项目1.ncnn2.mnn 总结 前言 yolov7 pytorch模型转onnx&#xff0c;转ncnn模型和mnn模型使用细节&#xff0c;记录一下 git仓库&#xff1a; yolov7 https://github.com/WongKinYiu/yolov7 n…

如何基于G6进行双树流转绘制? | 京东云技术团队

1. 背景 业务背景&#xff1a;CRM系统随着各业务条线对线索精细化分配的诉求逐渐增加&#xff0c;各个条线的流向规则会越来越复杂&#xff0c;各个条线甚至整个CRM的线索流转规则急需一种树形的可视化的图来表达。 技术背景&#xff1a;在开发之前考虑了三种方案&#xff0c;…

选什么样的软件平台开发能让办公效率得到提升?

在当今快节奏的时代中&#xff0c;办公自动化发展已成为趋势&#xff0c;采用什么样的软件平台开发能让办公效率得到大大提升&#xff1f;面对众多粉丝朋友提出的问题&#xff0c;作为低代码开发平台服务商&#xff0c;流辰信息有责任有义务与大家分享好产品。因为这是能提升办…

GPT现状终于有人讲清楚了!OpenAI大牛最新演讲爆火,还得是马斯克钦点的天才

量子位 | 公众号 QbitAI 继Windows Copilot发布后&#xff0c;微软Build大会热度又被一场演讲引爆。 前特斯拉AI总监Andrej Karpathy在演讲中认为思维树&#xff08;tree of thoughts&#xff09;与AlphaGo的蒙特卡洛树搜索&#xff08;MCTS&#xff09;有异曲同工之妙&#…

MySQL数据库 4.SQL通用语法及分类

目录 &#x1f914;SQL通用语法&#xff1a; &#x1f60a;语句&#xff1a; &#x1f60a;注释&#xff1a; &#x1f914;SQL语句分类&#xff1a; &#x1f60a;1.DDL语句&#xff1a; &#x1f60a;2.DML语句&#xff1a; &#x1f60a;3.DQL语言&#xff1a; &…

springboot+vue+element-ui在线招投标系统

本在线招投标系统管理员管理个人中心&#xff0c;投标人管理&#xff0c;招标人管理&#xff0c;评标人管理&#xff0c;招标信息管理&#xff0c;投标信息管理&#xff0c;评标信息管理&#xff0c;中标信息管理&#xff0c;系统管理。管理员负责所有的管理信息&#xff0c;招…