网络编程:服务器模型-并发服务器-多进程

news2024/10/5 20:19:58

并发服务器概念:

并发服务器同一时刻可以处理多个客户机的请求

设计思路:

并发服务器是在循环服务器基础上优化过来的

(1)每连接一个客户机,服务器立马创建子进程或者子线程来跟新的客户机通信 (accept之后的),服务器不会与客户端进行通信!!!

(2)IO多路复用技术

1、多进程实现并发服务器

思想:

主进程专门用于连接多个客户端的请求,若有一路客户端连接进来,主进程就创建一个子进程,用该子进程来处理该客户端的业务数据。

回顾:创建进程

 #include <sys/types.h>

 #include <unistd.h>

    pid_t fork(void);
    功能:创建一个子进程
    参数:无
    返回值:pid_t就是int类型的别名
        返回值大于0,代表此时是父进程,该值的含义为创建成功的子进程的ID号
        返回值等于0,代表此时是子进程
        返回值小于0,创建失败可以perror

源代码:

tcp_server.c 

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>//sockaddr_in
#include <unistd.h>
#include <arpa/inet.h>   // 包含 inet_addr 函数的声明 
#include <sys/select.h>
#include <sys/time.h>
#define BUF_SIZE 20

int main(int argc, const char *argv[])
{
	//1.socket
	int iServer = socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == iServer){
		puts("----------1、create socket error!");
		return -1;
	}
	printf("----------1、create socket ok! iServer:%d", iServer);//0,1,2标准输入输出出错,iServer为3

	//2.bind
	struct sockaddr_in stServer;
	stServer.sin_family = AF_INET;//第一个成员
	stServer.sin_port = htons(8888);//第二个成员
	stServer.sin_addr.s_addr = inet_addr("127.0.0.1");//将点分十进制ip地址转换为32位无符号整数
	int ret = bind(iServer, (struct sockaddr *)&stServer, sizeof(struct sockaddr));
	if(-1 == ret){
		puts("----------2、bind error!");
		return -1;
	}
	puts("----------2、bind ok!");

	//3.listen
	ret = listen(iServer, 5);
	if(-1 == ret){
		puts("----------3、listen error!");
		return -1;
	}
	puts("----------3、listen ok!");

	//4.accept
	struct sockaddr_in stClient;//存放对方的主机信息
	socklen_t len = sizeof(struct sockaddr_in);
	char buf[BUF_SIZE] = {0};
	fd_set stFdr;//文件描述符集合表,大小1024
	FD_ZERO(&stFdr);//将文件描述符集合表中所有内容清零
	while(1){
		FD_SET(iServer, &stFdr);
		FD_SET(0, &stFdr);
		//select
		ret = select(iServer + 1, &stFdr, NULL, NULL, NULL);

		if(ret <= 0){
			continue;
		}

		printf("select ok, ret = %d\r\n", ret);

		//FD_ISSET
		if(FD_ISSET(0, &stFdr)){
			memset(buf, 0, BUF_SIZE);
			fgets(buf, BUF_SIZE, stdin);
			printf("fgets ok, data = %s\r\n", buf);
		}

		if(FD_ISSET(iServer, &stFdr)){
			int iClient = accept(iServer, (struct sockaddr *)&stClient, &len);
			if(-1 == iClient){
				continue;//当前客户端出错转向下一个客户端	
			}
			printf("----------4、accept ok! iClient = %d\r\n",iClient );//标准输入输出出错,所以下一个打开的文件一定是3
			//5.recv/send
			ret = recv(iClient, buf, BUF_SIZE, 0);
			if(ret <= 0){
				close(iClient);
				continue;
			}
			printf("----------recv data ok! buf = %s\r\n",buf);
			//send
			ret = send(iClient, buf, BUF_SIZE, 0);
			if(ret <= 0){
				close(iClient);
				continue;
			}
			printf("----------send data ok! %s\r\n",buf);
			//close(iClient);//断开当前客户端

		}


	}

	return 0;
}


tcp_client.c

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>




#define BUF_SIZE 20
//main函数参数,如果需要键入IP则给定即可
int main(int argc, const char *argv[])
{
	//1、socket
	int iClient = 	socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == iClient){
		puts("----------1、create socket error!");
		return -1;
	}
	puts("----------1、create socket ok!");

	//2、connect
	struct sockaddr_in stServer;
	stServer.sin_family = AF_INET;
	stServer.sin_port = htons(8888);
	//stServer.sin_addr.s_addr = inet_addr("192.168.15.71");
	stServer.sin_addr.s_addr = inet_addr("127.0.0.1");
	int ret = connect(iClient, (struct sockaddr *)&stServer, sizeof(struct sockaddr_in));
	if(-1 == ret){
		puts("----------2、connect error!");
		return -1;
	}
	puts("----------2、connect ok!");

	char buf[BUF_SIZE] = {0};
	while(1){
		//gets();
		//char *fgets(char *s, int size, FILE *stream);
		fgets(buf, BUF_SIZE, stdin);//更安全,边界检查

		//3、send recv
		ret = send(iClient, buf, BUF_SIZE, 0);
		if(-1 == ret){
			puts("----------3、send data error!");
		}
		printf("----------3、send data ok! buf = %s\r\n",buf);

		//recv
		//函数原型:ssize_t recv(int sockfd, void *buf, size_t len, int flags);
		memset(buf, 0, BUF_SIZE);
		ret = recv(iClient, buf, BUF_SIZE, 0);
		if(-1 == ret){
			puts("----------4、recv error!");
			return -1;
		}
		printf("----------4、recv data ok! buf = %s\r\n",buf);
	}
	close(iClient);

	return 0;
}

思考:

多进程并发服务器的缺点:每连接一个客户端,就为其创建子进程,客户端数量比较大时,服务器的运 行效率就会变低。

注:

以上代码只能实现:

        ①客户端连接到服务器端,只能发送一条数据,之后发送不成功

        ②服务器端可以检测标准输入给自己

测试结果如下图:

2、多进程实现并发服务器-优化版本

tcp_server.c 

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>//sockaddr_in
#include <unistd.h>
#include <arpa/inet.h>   // 包含 inet_addr 函数的声明 
#include <sys/select.h>
#include <sys/time.h>
#define BUF_SIZE 20

int main(int argc, const char *argv[])
{
	//1.socket
	int iServer = socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == iServer){
		puts("----------1、create socket error!");
		return -1;
	}
	printf("----------1、create socket ok! iServer:%d", iServer);//0,1,2标准输入输出出错,iServer为3

	//2.bind
	struct sockaddr_in stServer;
	stServer.sin_family = AF_INET;//第一个成员
	stServer.sin_port = htons(9999);//第二个成员
	stServer.sin_addr.s_addr = inet_addr("127.0.0.1");//将点分十进制ip地址转换为32位无符号整数
	int ret = bind(iServer, (struct sockaddr *)&stServer, sizeof(struct sockaddr));
	if(-1 == ret){
		puts("----------2、bind error!");
		return -1;
	}
	puts("----------2、bind ok!");

	//3.listen
	ret = listen(iServer, 5);
	if(-1 == ret){
		puts("----------3、listen error!");
		return -1;
	}
	puts("----------3、listen ok!");

	//4.accept
	struct sockaddr_in stClient;//存放对方的主机信息
	socklen_t len = sizeof(struct sockaddr_in);
	char buf[BUF_SIZE] = {0};
	fd_set stFdr;//文件描述符集合表,大小1024
	FD_ZERO(&stFdr);//将文件描述符集合表中所有内容清零
	FD_SET(iServer, &stFdr);//iServer添加到原文件描述符集合表中
	int max = iServer;
	while(1)
	{
		//select
		fd_set stFdrTmp = stFdr;	//定义临时文件描述符集合表
		ret = select(max + 1, &stFdrTmp, NULL, NULL, NULL);

		if(ret <= 0)
		{
			printf("select error!\r\n");
			continue;
		}

		printf("select ok, ret = %d\r\n", ret);

		int i = 0;
		for(i = 0; i < max + 1; i++)
		{
			if(FD_ISSET(i, &stFdrTmp))
			{	 // 循环判断哪个文件描述符被置位
				//操作
				if(i == iServer)
				{ 
					// i == 3, 操作
					int iClient = accept(iServer, (struct sockaddr *)&stClient, &len);
					if(-1 == iClient)
					{
						continue;//当前客户端出错转向下一个客户端	
					}
					printf("----------4、accept ok! iClient = %d\r\n",iClient );//标准输入输出出错,所以下一个打开的文件一定是4
					FD_SET(iClient, &stFdr);
					//更新max
					if(max < iClient)
					{
						max = iClient;
					}
				}
				else
				{ // 与多个客户端保持连接
					//recv/send
					ret = recv(i, buf, BUF_SIZE, 0);

					if(ret > 0)
					{
						printf("recv:%s\r\n", buf);
						send(i, buf, BUF_SIZE, 0);
					}
					else
					{
						close(i);
						FD_CLR(i, &stFdr);
					}

				}
			}

		}
	}
	return 0;
}

tcp_client.c

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>




#define BUF_SIZE 20
//main函数参数,如果需要键入IP则给定即可
int main(int argc, const char *argv[])
{
	//1、socket
	int iClient = 	socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == iClient){
		puts("----------1、create socket error!");
		return -1;
	}
	puts("----------1、create socket ok!");

	//2、connect
	struct sockaddr_in stServer;
	stServer.sin_family = AF_INET;
	stServer.sin_port = htons(9999);
	//stServer.sin_addr.s_addr = inet_addr("192.168.15.71");
	//stServer.sin_addr.s_addr = inet_addr("192.168.15.71");
	stServer.sin_addr.s_addr = inet_addr("127.0.0.1");
	int ret = connect(iClient, (struct sockaddr *)&stServer, sizeof(struct sockaddr_in));
	if(-1 == ret){
		puts("----------2、connect error!");
		return -1;
	}
	puts("----------2、connect ok!");

	char buf[BUF_SIZE] = {0};
	while(1){
		//gets();
		//char *fgets(char *s, int size, FILE *stream);
		fgets(buf, BUF_SIZE, stdin);//更安全,边界检查

		//3、send recv
		ret = send(iClient, buf, BUF_SIZE, 0);
		if(-1 == ret){
			puts("----------3、send data error!");
		}
		printf("----------3、send data ok! buf = %s\r\n",buf);

		//recv
		//函数原型:ssize_t recv(int sockfd, void *buf, size_t len, int flags);
		memset(buf, 0, BUF_SIZE);
		ret = recv(iClient, buf, BUF_SIZE, 0);
		if(-1 == ret){
			puts("----------4、recv error!");
			return -1;
		}
		printf("----------4、recv data ok! buf = %s\r\n",buf);
	}
	close(iClient);

	return 0;
}

注:

以上代码可以实现:

        ①多个客户端与服务器连接 并 发送&回显数据

测试结果如下图:

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

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

相关文章

达梦数据库 报错 数据类型不匹配

达梦数据库 报错 数据类型不匹配 背景描述问题分析问题处理方案1&#xff1a;方案2&#xff1a;TO_CHAR(str)CAST(value AS type)CONVERT(type,value)DBMS_LOB 包TEXT_EQUAL(n1,n2) 写在最后 背景描述 本文写于初接触到达梦(DM)数据库&#xff0c;之前没有用过&#xff0c;因此…

网络协议的分类

1.概要 网络协议可以分为三类&#xff1a; 封装协议路由协议功能类协议 2.分类说明 OSPF报文直接调用_ IP协议__协议进行封装&#xff0c;以目的地址_244.0.0.5 __发送到所有的OSPF路由器? 244.0.0.1 所有主机&#xff1b;244.0.0.2 所有路由器&#xff1b;244.0.0.6 指定…

SpringSecurity6集成数据库

本文章对应视频可在B站查看SpringSecurity6对应视频教程&#xff0c;记得三连哦&#xff0c;这对我很重要呢&#xff01; 温馨提示&#xff1a;视频与文章相辅相成&#xff0c;结合学习效果更强哦&#xff01; 系列文章链接 1、初识SpringSecurity&#xff0c;认识主流Java权限…

win10系统解除微软账户和本地账户绑定

折腾了好久&#xff0c;终于找到一种方法可以退出微软账号了&#xff0c;不过这种方法我测试是成功的&#xff0c;有人留言自己不成功&#xff0c;具体解决方法只能看这些留言了 win10当中没有注销按钮&#xff0c;win x 弹出的菜单里面有关闭或注销&#xff0c;可以选择注销…

Unity射击游戏开发教程:(15)添加推进器推进和推进器推进动画

这是一个可以添加到我的游戏中的简单而有趣的功能。当玩家按住 Shift 按钮时,速度会加快,松开 Shift 按钮时,速度会恢复到原来的速度。 这需要不同的输入检测。通常使用的是Input.GetKeyDown并传入你想要获取的key。这只会检测在当前帧期间是否按下了按钮,但如果按住,将不…

Hive的join操作

假设有三张表&#xff0c;结构和数据如下&#xff1a;-- 创建表 test_a,test_b,test_c CREATE TABLE test_a( id int, name string ) ROW FORMAT DELIMITED FIELDS TERMINATED BY \t;--分别导入数据到三个表中 --test_a 1 a1 2 a2 4 a4 --test_b 1 b1 3 b3 4 b4 --…

Ubuntu 20.04在Anaconda虚拟环境中配置PyQt4

一、创建一个虚拟环境 1 创建一个python2.7的虚拟环境&#xff1a; conda create -n pyqt4 numpy matplotlib python2.72 在环境中安装几个需要的包&#xff1a; pip install Theano pip install python-opencv3.4.0.14 pip install qdarkstyle pip install dominate二、在主…

打造清洁宜居家园保护自然生态环境,基于YOLOv7【tiny/l/x】参数系列模型开发构建自然生态场景下违规违法垃圾倾倒检测识别系统

自然生态环境&#xff0c;作为我们人类赖以生存的家园&#xff0c;其健康与否直接关系到我们的生活质量。然而&#xff0c;近年来&#xff0c;一些不法分子为了个人私利&#xff0c;在河边、路边等公共区域肆意倾倒垃圾&#xff0c;严重破坏了环境的健康与平衡。这种行为不仅损…

【Python探索之旅】选择结构(条件语句)

文章目录 条件结构&#xff1a; 1.1 if单分支结构 1.2 if-else 多分支结构 1.3 if-elif 多重结构&#xff1a; 完结撒花​ 前言 Python条件语句是通过一条或多条语句的执行结果&#xff08;True或者False&#xff09;来决定执行的代码块。 Python提供了顺序、选择、循环三…

2024.5.19 机器学习周报

引言 Abstract 文献阅读 1、题目 X-HRNET: TOWARDS LIGHTWEIGHT HUMAN POSE ESTIMATION WITH SPATIALLY UNIDIMENSIONAL SELF-ATTENTION 2、引言 高分辨率表示是人体姿态估计实现高性能所必需的&#xff0c;随之而来的问题是高计算复杂度。特别地&#xff0c;主要的姿态估…

AI算法-高数5.1-线性代数-向量间的关系

线性代数基础概念见&#xff1a;AI算法-高数5-线性代数1-基本概念、向量-CSDN博客 宋浩老师课程学习&#xff1a; 3.2 向量间的线性关系&#xff08;一&#xff09;_哔哩哔哩_bilibili 向量间的关系&#xff1a; ​ ​ ​ ​ 判断向量贝塔(β)是否是阿尔法(α)的线性组…

4.2 试编写一程序,要求比较两个字符串STRING1和STRING2所含字符是否相同,若相同则显示“MATCH”,若不相同则显示“NO MATCH”

方法一&#xff1a;在程序内部设置两个字符串内容&#xff0c;终端返回是否匹配 运行效果&#xff1a; 思路&#xff1a; 1、先比较两个字符串的长度&#xff0c;如果长度不一样&#xff0c;则两组字符串肯定不匹配&#xff1b;如果长度一样&#xff0c;再进行内容的匹配 2、如…

红外遥控和LCD1602

26.1.1 红外线简介 人的眼睛能看到的可见光按波长从长到短排列&#xff0c;依次为红、橙、黄、绿、青、蓝、紫。其中红光的波长范围为 0.62&#xff5e;0.76μm&#xff1b;紫光的波长范围为 0.38&#xff5e;0.46μm。比紫光波长还短的光叫紫外线&#xff0c;比红光波长还长的…

利用光学和SAR数据进行亚马逊热带雨林监测

亚马逊热带雨林&#xff0c;670万平方公里&#xff0c;物种丰富&#xff0c;森林历史悠久。巴西环保局用光学和SAR数据进行森林监测&#xff0c;主要监测森林砍伐范围、人为破坏、非法采矿和隐蔽的飞机跑道。 图 2011年12月森林砍伐范围 在SAR强度数据上&#xff0c;被砍伐的森…

C#语言进阶

一、简单数据结构类 1. ArrayList ArrayList是一个 C# 为我们封装好的类&#xff0c;它的本质是一个 object 类型的数组。ArrayList类帮助我们实现了很多方法&#xff0c;比如数组的增删查改 1.1 声明 using System.Collections;ArrayList array new ArrayList(); 1.2 增…

RabbitMQ--死信队列

目录 一、死信队列介绍 1.死信 2.死信的来源 2.1 TTL 2.2 死信的来源 3.死信队列 4.死信队列的用途 二、死信队列的实现 1.导入依赖 pom.xml 2.application.properties 3.配置类 4.生产者 5.业务消费者&#xff08;正常消费者&#xff09; 6.死信队列消费者 一、…

STM32-LCD液晶屏(ILI9341)

MCU&#xff1a;STM32F103VET6 开发环境&#xff1a;STM32CubeMXMDK5 目录 STM32液晶屏LCD&#xff08;ILI9341&#xff09; LCD液晶显示 液晶控制原理 ILI9341液晶控制器简介 8080写时序 8080读时序 FSMC模拟8080时序 液晶屏的信号线 STM32CubeMX配置FSMC 测试部分 …

工作玩手机监测识别摄像机

工作场所的员工玩手机已经成为了一种常见的现象&#xff0c;特别是在办公室、生产车间等地方。而这种现象不仅仅影响了员工的工作效率&#xff0c;还可能会对工作安全造成一定的隐患。为了监测和识别员工玩手机的情况&#xff0c;工作玩手机监测识别摄像机应运而生。工作玩手机…

05 | 如何确保消息不会丢失?

检测消息丢失的方法 我们可以利用消息队列的有序性来验证是否有消息丢失。在 Producer 端,我们给每个发出的消息附加一个连续递增的序号,然后在 Consumer 端来检查这个序号的连续性。 如果没有消息丢失,Consumer 收到消息的序号必然是连续递增的,或者说收到的消息,其中的…

物联网实战--平台篇之(六)应用管理后台

目录 一、应用数据库 二、登录记忆 三、新建应用 四、获取应用列表 五、重命名应用 本项目的交流QQ群:701889554 物联网实战--入门篇https://blog.csdn.net/ypp240124016/category_12609773.html 物联网实战--驱动篇https://blog.csdn.net/ypp240124016/category_126313…