网络编程:服务器模型-并发服务器-多进程
并发服务器概念:
并发服务器同一时刻可以处理多个客户机的请求
设计思路:
并发服务器是在循环服务器基础上优化过来的
(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;
}
注:
以上代码可以实现:
①多个客户端与服务器连接 并 发送&回显数据
测试结果如下图:

相关文章:
网络编程:服务器模型-并发服务器-多进程
并发服务器概念: 并发服务器同一时刻可以处理多个客户机的请求 设计思路: 并发服务器是在循环服务器基础上优化过来的 (1)每连接一个客户机,服务器立马创建子进程或者子线程来跟新的客户机通信 (accept之后…...
React 基础案例
React的特点: 1、声明式编程 2、组件化开发 3、多平台适配yuan 原生实现: <h2 class"title"></h2><button class"btn">改变文本</button><script>let msg "Hello World";const titleEl d…...
【Python探索之旅】选择结构(条件语句)
文章目录 条件结构: 1.1 if单分支结构 1.2 if-else 多分支结构 1.3 if-elif 多重结构: 完结撒花 前言 Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。 Python提供了顺序、选择、循环三…...
Recommender ~ Collaborative filtering
Using per-item features User j 预测 movie i: Cost Function: 仅求和用户投票过的电影。 常规规范化(usual normalization):1/2m 正则化项:阻止过拟合 在知晓X的前提下,如何学习w,b参数…...
我觉得POC应该贴近实际
今天我看到一位老师给我一份测试数据。 这是三个国产数据库。算是分布式的。其中有两个和我比较熟悉,但是这个数据看上去并不好。看上去第一个黄色的数据库数据是这里最好的了。但是即使如此,我相信大部分做数据库的人都知道。MySQL和PostgreSQL平时拿出…...
AI 情感聊天机器人工作之旅 —— 与复读机问题的相遇与别离
前言:先前在杭州的一家大模型公司从事海外闲聊机器人产品,目前已经离职,文章主要讨论在闲聊场景下遇到的“复读机”问题以及一些我个人的思考和解决方案。文章内部已经对相关公司和人员信息做了去敏,如仍涉及到机密等情况…...
如何使用ArcGIS Pro进行选房分析
无论是研究城市规划布局还是寻找理想的住房,都需要综合考虑购物、医疗、教育和休闲等多方面因素,此时我们的GIS软件就可以派上用场了,这里为大家介绍一下如何使用 ArcGIS Pro 进行选房分析,希望能对你有所帮助。 数据来源 教程所…...
android图标底色问题,debug与release不一致
背景 在android 8(sdk 26)之前的版本,直接使用图片文件作为图标,开发时比较容易控制图标,但是不同的安卓定制版本就不容易统一图标风格了。 在android 8及之后的版本,图标对应的是ic_launcher.xml&#x…...
如何提高自己的全局视野?
以下是一些可以帮助提高全局视野的方法: 1. 广泛学习不同领域知识:包括但不限于技术相关的各个领域、业务知识、行业动态等,拓宽知识面。 2. 参与大型项目:积极投身到复杂的、规模较大的项目中,在实践中感受和理解系…...
element ui的确认提示框文字样式修改
修改确认提示框文字样式修改,使用message属性修改: 例: js代码: this.$msgbox({title: 确定要删除吗?,message: this.$createElement(p, null, [this.$createElement(span, { style: color: red }, 该素材一旦删除,…...
Typescript 哲学 - ts模块使用最佳实践
ts的作用域 默认是全局(global),这也是为什么在 两个ts文件声明同一个变量报错变量名冲突,解决方法是使某个文件以模块的形式存在(文件顶层使用 export 、import ) In TypeScript, just as in ECMAScript 2…...
自动驾驶决策规划——坐标转换
以下内容来自b站up主忠厚老实的老王,视频链接:自动驾驶决策规划算法序章 总纲与大致目录_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1hP4y1p7es/?spm_id_from333.999.0.0&vd_sourced36e625f376908cfa88ef5ecf2fb0ed8侵删。 决策规划算法…...
信创应用软件之邮箱
信创应用软件之邮箱 文章目录 信创应用软件之邮箱采用信创邮箱的必要性信创邮箱采购需求国产邮箱业务形态国产邮箱代表性品牌CoremailRichmail安宁eyouUMail拓波 邮件安全的发展阶段 采用信创邮箱的必要性 邮箱是天然的数据存储空间,党政和央国企客户在使用过程中存…...
TriCore: Architecture
说明 本文是 英飞凌 架构文档 TriCore TC162P core archiecture Volume 1 of 2 (infineon.com) 的笔记,稍作整理方便查阅,错误之处,还请指正,谢谢 :) 1. Architecture 2. General Purpose & System Register 名词列表&#…...
16进制与不同进制之间计算加减乘除的比较快的方法
方法: 1.加分、减法: 将所有的进制的数转成目标进制的数,然后按位加。 如 0x123 0x1234 0x1357 2.乘法、除法: 将所有的进制的数转成二进制数,然后进行移位。 如 0x123456 乘 32(十进制)…...
责任链模式:原理与实现解析,及其应用场景代入
责任链模式的作用:复用和扩展,在实际的项目开发中比较常用,特别是框架开发中,我们可以利用它们来提供框架的扩展点,能够让框架的使用者在不修改框架源码的情况下,基于扩展点定制化框架的功能。 这里主要介…...
从心理学角度看,GPT 对人有什么影响?
开启个性化AI体验:深入了解GPT的无限可能 导言 GPT 与我们日常生活的融合标志着技术进步的重大飞跃,为提高效率和创新提供了前所未有的机遇。然而,当我们与这些智能系统日益紧密地交织在一起时,探索它们对个人产生的细微的心理影响…...
【C语言/数据结构】栈:从概念到两种存储结构的实现
目录 一、栈的概念 二、栈的两种实现方式 1.顺序表实现栈 2.链表实现栈 三、栈的顺序存储结构及其实现 1.栈的声明 2.栈的初始化 3.栈的销毁 4.栈的压栈 5.栈的弹栈 6.栈的判空 7.返回栈顶元素 8.返回栈的长度 四、栈的链式存储结构及其实现 1.栈的声明 2.栈的…...
47. UE5 RPG 实现角色死亡效果
在上一篇文章中,我们实现了敌人受到攻击后会播放受击动画,并且还给角色设置了受击标签。并在角色受击时,在角色身上挂上受击标签,在c里,如果挂载了此标签,速度将降为0 。 受击有了,接下来我们将…...
C语言/数据结构——每日一题(环形链表)
一.前言 今天在力扣上刷到一道链表题——环形链表https://leetcode.cn/problems/linked-list-cycle 想着和大家们分享一下。让我们直接开始今天的分享吧。、 二.正文 1.1题目描述 1.2题目分析 这道题是想让我们做出分析,该链表是不是带环链表,如果是…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
