当前位置: 首页 > news >正文

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

并发服务器概念:

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

设计思路:

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

(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 20int main(int argc, const char *argv[])
{//1.socketint 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.bindstruct 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.listenret = listen(iServer, 5);if(-1 == ret){puts("----------3、listen error!");return -1;}puts("----------3、listen ok!");//4.acceptstruct sockaddr_in stClient;//存放对方的主机信息socklen_t len = sizeof(struct sockaddr_in);char buf[BUF_SIZE] = {0};fd_set stFdr;//文件描述符集合表,大小1024FD_ZERO(&stFdr);//将文件描述符集合表中所有内容清零while(1){FD_SET(iServer, &stFdr);FD_SET(0, &stFdr);//selectret = select(iServer + 1, &stFdr, NULL, NULL, NULL);if(ret <= 0){continue;}printf("select ok, ret = %d\r\n", ret);//FD_ISSETif(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/sendret = recv(iClient, buf, BUF_SIZE, 0);if(ret <= 0){close(iClient);continue;}printf("----------recv data ok! buf = %s\r\n",buf);//sendret = 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、socketint iClient = 	socket(AF_INET, SOCK_STREAM, 0);if(-1 == iClient){puts("----------1、create socket error!");return -1;}puts("----------1、create socket ok!");//2、connectstruct 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 recvret = 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 20int main(int argc, const char *argv[])
{//1.socketint 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.bindstruct 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.listenret = listen(iServer, 5);if(-1 == ret){puts("----------3、listen error!");return -1;}puts("----------3、listen ok!");//4.acceptstruct sockaddr_in stClient;//存放对方的主机信息socklen_t len = sizeof(struct sockaddr_in);char buf[BUF_SIZE] = {0};fd_set stFdr;//文件描述符集合表,大小1024FD_ZERO(&stFdr);//将文件描述符集合表中所有内容清零FD_SET(iServer, &stFdr);//iServer添加到原文件描述符集合表中int max = iServer;while(1){//selectfd_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 );//标准输入输出出错,所以下一个打开的文件一定是4FD_SET(iClient, &stFdr);//更新maxif(max < iClient){max = iClient;}}else{ // 与多个客户端保持连接//recv/sendret = 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、socketint iClient = 	socket(AF_INET, SOCK_STREAM, 0);if(-1 == iClient){puts("----------1、create socket error!");return -1;}puts("----------1、create socket ok!");//2、connectstruct 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 recvret = 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;
}

注:

以上代码可以实现:

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

测试结果如下图:

相关文章:

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

并发服务器概念&#xff1a; 并发服务器同一时刻可以处理多个客户机的请求 设计思路&#xff1a; 并发服务器是在循环服务器基础上优化过来的 &#xff08;1&#xff09;每连接一个客户机&#xff0c;服务器立马创建子进程或者子线程来跟新的客户机通信 &#xff08;accept之后…...

React 基础案例

React的特点&#xff1a; 1、声明式编程 2、组件化开发 3、多平台适配yuan 原生实现&#xff1a; <h2 class"title"></h2><button class"btn">改变文本</button><script>let msg "Hello World";const titleEl d…...

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

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

Recommender ~ Collaborative filtering

Using per-item features User j 预测 movie i&#xff1a; Cost Function: 仅求和用户投票过的电影。 常规规范化&#xff08;usual normalization&#xff09;&#xff1a;1/2m 正则化项&#xff1a;阻止过拟合 在知晓X的前提下&#xff0c;如何学习w&#xff0c;b参数…...

我觉得POC应该贴近实际

今天我看到一位老师给我一份测试数据。 这是三个国产数据库。算是分布式的。其中有两个和我比较熟悉&#xff0c;但是这个数据看上去并不好。看上去第一个黄色的数据库数据是这里最好的了。但是即使如此&#xff0c;我相信大部分做数据库的人都知道。MySQL和PostgreSQL平时拿出…...

AI 情感聊天机器人工作之旅 —— 与复读机问题的相遇与别离

前言&#xff1a;先前在杭州的一家大模型公司从事海外闲聊机器人产品&#xff0c;目前已经离职&#xff0c;文章主要讨论在闲聊场景下遇到的“复读机”问题以及一些我个人的思考和解决方案。文章内部已经对相关公司和人员信息做了去敏&#xff0c;如仍涉及到机密等情况&#xf…...

如何使用ArcGIS Pro进行选房分析

无论是研究城市规划布局还是寻找理想的住房&#xff0c;都需要综合考虑购物、医疗、教育和休闲等多方面因素&#xff0c;此时我们的GIS软件就可以派上用场了&#xff0c;这里为大家介绍一下如何使用 ArcGIS Pro 进行选房分析&#xff0c;希望能对你有所帮助。 数据来源 教程所…...

android图标底色问题,debug与release不一致

背景 在android 8&#xff08;sdk 26&#xff09;之前的版本&#xff0c;直接使用图片文件作为图标&#xff0c;开发时比较容易控制图标&#xff0c;但是不同的安卓定制版本就不容易统一图标风格了。 在android 8及之后的版本&#xff0c;图标对应的是ic_launcher.xml&#x…...

如何提高自己的全局视野?

以下是一些可以帮助提高全局视野的方法&#xff1a; 1. 广泛学习不同领域知识&#xff1a;包括但不限于技术相关的各个领域、业务知识、行业动态等&#xff0c;拓宽知识面。 2. 参与大型项目&#xff1a;积极投身到复杂的、规模较大的项目中&#xff0c;在实践中感受和理解系…...

element ui的确认提示框文字样式修改

修改确认提示框文字样式修改&#xff0c;使用message属性修改&#xff1a; 例&#xff1a; js代码&#xff1a; this.$msgbox({title: 确定要删除吗?,message: this.$createElement(p, null, [this.$createElement(span, { style: color: red }, 该素材一旦删除&#xff0c;…...

Typescript 哲学 - ts模块使用最佳实践

ts的作用域 默认是全局&#xff08;global&#xff09;&#xff0c;这也是为什么在 两个ts文件声明同一个变量报错变量名冲突&#xff0c;解决方法是使某个文件以模块的形式存在&#xff08;文件顶层使用 export 、import &#xff09; In TypeScript, just as in ECMAScript 2…...

自动驾驶决策规划——坐标转换

以下内容来自b站up主忠厚老实的老王&#xff0c;视频链接&#xff1a;自动驾驶决策规划算法序章 总纲与大致目录_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1hP4y1p7es/?spm_id_from333.999.0.0&vd_sourced36e625f376908cfa88ef5ecf2fb0ed8侵删。 决策规划算法…...

信创应用软件之邮箱

信创应用软件之邮箱 文章目录 信创应用软件之邮箱采用信创邮箱的必要性信创邮箱采购需求国产邮箱业务形态国产邮箱代表性品牌CoremailRichmail安宁eyouUMail拓波 邮件安全的发展阶段 采用信创邮箱的必要性 邮箱是天然的数据存储空间&#xff0c;党政和央国企客户在使用过程中存…...

TriCore: Architecture

说明 本文是 英飞凌 架构文档 TriCore TC162P core archiecture Volume 1 of 2 (infineon.com) 的笔记&#xff0c;稍作整理方便查阅&#xff0c;错误之处&#xff0c;还请指正&#xff0c;谢谢 :) 1. Architecture 2. General Purpose & System Register 名词列表&#…...

16进制与不同进制之间计算加减乘除的比较快的方法

方法&#xff1a; 1.加分、减法&#xff1a; 将所有的进制的数转成目标进制的数&#xff0c;然后按位加。 如 0x123 0x1234 0x1357 2.乘法、除法&#xff1a; 将所有的进制的数转成二进制数&#xff0c;然后进行移位。 如 0x123456 乘 32&#xff08;十进制&#xff09;…...

责任链模式:原理与实现解析,及其应用场景代入

责任链模式的作用&#xff1a;复用和扩展&#xff0c;在实际的项目开发中比较常用&#xff0c;特别是框架开发中&#xff0c;我们可以利用它们来提供框架的扩展点&#xff0c;能够让框架的使用者在不修改框架源码的情况下&#xff0c;基于扩展点定制化框架的功能。 这里主要介…...

从心理学角度看,GPT 对人有什么影响?

开启个性化AI体验&#xff1a;深入了解GPT的无限可能 导言 GPT 与我们日常生活的融合标志着技术进步的重大飞跃&#xff0c;为提高效率和创新提供了前所未有的机遇。然而&#xff0c;当我们与这些智能系统日益紧密地交织在一起时&#xff0c;探索它们对个人产生的细微的心理影响…...

【C语言/数据结构】栈:从概念到两种存储结构的实现

目录 一、栈的概念 二、栈的两种实现方式 1.顺序表实现栈 2.链表实现栈 三、栈的顺序存储结构及其实现 1.栈的声明 2.栈的初始化 3.栈的销毁 4.栈的压栈 5.栈的弹栈 6.栈的判空 7.返回栈顶元素 8.返回栈的长度 四、栈的链式存储结构及其实现 1.栈的声明 2.栈的…...

47. UE5 RPG 实现角色死亡效果

在上一篇文章中&#xff0c;我们实现了敌人受到攻击后会播放受击动画&#xff0c;并且还给角色设置了受击标签。并在角色受击时&#xff0c;在角色身上挂上受击标签&#xff0c;在c里&#xff0c;如果挂载了此标签&#xff0c;速度将降为0 。 受击有了&#xff0c;接下来我们将…...

C语言/数据结构——每日一题(环形链表)

一.前言 今天在力扣上刷到一道链表题——环形链表https://leetcode.cn/problems/linked-list-cycle 想着和大家们分享一下。让我们直接开始今天的分享吧。、 二.正文 1.1题目描述 1.2题目分析 这道题是想让我们做出分析&#xff0c;该链表是不是带环链表&#xff0c;如果是…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

wpf在image控件上快速显示内存图像

wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像&#xff08;比如分辨率3000*3000的图像&#xff09;的办法&#xff0c;尤其是想把内存中的裸数据&#xff08;只有图像的数据&#xff0c;不包…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理

在城市的某个角落&#xff0c;一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延&#xff0c;滚滚浓烟弥漫开来&#xff0c;周围群众的生命财产安全受到严重威胁。就在这千钧一发之际&#xff0c;消防救援队伍迅速行动&#xff0c;而豪越科技消防一体化安全管控平台构建的消防“…...