【项目 计网7】4.20 多进程实现并发服务器 4.22 多线程实现并发服务器
文章目录
- 4.20 多进程实现并发服务器
- server_process.c
- client.c
- 4.22 多线程实现并发服务器
- 客户端代码:
- 服务端代码:
4.20 多进程实现并发服务器
要实现TCP通信服务器处理并发的任务,使用多线程或者多进程来解决。
思路:
1、一个父进程,多个子进程
2、父进程负责等待并接受客户端的连接
3、子进程:完成通信,接受一个客户端连接,就创建一个子进程用于通信
server_process.c
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <wait.h>
#include <errno.h>void recyleChild(int arg) {while(1) {int ret = waitpid(-1, NULL, WNOHANG);if(ret == -1) {// 所有的子进程都回收了break;}else if(ret == 0) {// 还有子进程活着break;} else if(ret > 0){// 被回收了printf("子进程 %d 被回收了\n", ret);}}
}int main() {//不能通过父进程进行子进程的回收,使用信号的方式进程子进程的回收//子进程结束时会发送SIGCHILDstruct sigaction act;act.sa_flags = 0;sigemptyset(&act.sa_mask);//临时阻塞的信号集,信号掩码清空act.sa_handler = recyleChild;// 注册信号捕捉sigaction(SIGCHLD, &act, NULL);// 创建socketint lfd = socket(PF_INET, SOCK_STREAM, 0);if(lfd == -1){perror("socket");exit(-1);}struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(9999);saddr.sin_addr.s_addr = INADDR_ANY;//0.0.0.0 ip地址// 绑定int ret = bind(lfd,(struct sockaddr *)&saddr, sizeof(saddr));if(ret == -1) {perror("bind");exit(-1);}// 监听ret = listen(lfd, 128);if(ret == -1) {perror("listen");exit(-1);}// 不断循环等待客户端连接while(1) {struct sockaddr_in cliaddr;int len = sizeof(cliaddr);// 接受连接int cfd = accept(lfd, (struct sockaddr*)&cliaddr, &len);if(cfd == -1) {//子进程结束,回收子进程,软中断,再回到accept会产生EINTR错误,若直接结束父进程,后续客户端将无法连接到服务端if(errno == EINTR) {continue;}perror("accept");exit(-1);}// 每一个连接进来,创建一个子进程跟客户端通信pid_t pid = fork();if(pid == 0) {// 子进程// 获取客户端的信息char cliIp[16];inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, cliIp, sizeof(cliIp));unsigned short cliPort = ntohs(cliaddr.sin_port);printf("client ip is : %s, prot is %d\n", cliIp, cliPort);// 接收客户端发来的数据char recvBuf[1024];while(1) {int len = read(cfd, &recvBuf, sizeof(recvBuf));if(len == -1) {perror("read");exit(-1);}else if(len > 0) {printf("recv client : %s\n", recvBuf);} else if(len == 0) {printf("client closed....\n");break;}write(cfd, recvBuf, strlen(recvBuf) + 1);//回写回去,+1将\0也放进去}close(cfd);exit(0); // 退出当前子进程}}close(lfd);return 0;
}
int cfd = accept(lfd, (struct sockaddr*)&cliaddr, &len);if(cfd == -1) {//在系统调用获取到有效连接之前,被信号打断。也就是accept本来阻塞着,程序中断去处理回收子进程。//再回来以后,accept就会产生一个EINTR错误。此时cfd == -1 ,会被判断为有误,直接exit,直接结束父进程,后续客户端将无法连接到服务端//所以这里需要加一个判断if(errno == EINTR) {continue;}perror("accept");exit(-1);}
client.c
// TCP通信的客户端
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main() {// 1.创建套接字int fd = socket(AF_INET, SOCK_STREAM, 0);if(fd == -1) {perror("socket");exit(-1);}// 2.连接服务器端struct sockaddr_in serveraddr;serveraddr.sin_family = AF_INET;inet_pton(AF_INET, "192.168.139.132", &serveraddr.sin_addr.s_addr);serveraddr.sin_port = htons(9999);int ret = connect(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));if(ret == -1) {perror("connect");exit(-1);}// 3. 通信char recvBuf[1024];int i = 0;while(1) {sprintf(recvBuf, "data : %d\n", i++);// 给服务器端发送数据write(fd, recvBuf, strlen(recvBuf)+1);int len = read(fd, recvBuf, sizeof(recvBuf));if(len == -1) {perror("read");exit(-1);} else if(len > 0) {printf("recv server : %s\n", recvBuf);} else if(len == 0) {// 表示服务器端断开连接printf("server closed...");break;}sleep(1);}// 关闭连接close(fd);return 0;
}
4.22 多线程实现并发服务器
客户端代码:
// TCP通信的客户端
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main() {// 1.创建套接字int fd = socket(AF_INET, SOCK_STREAM, 0);if(fd == -1) {perror("socket");exit(-1);}// 2.连接服务器端struct sockaddr_in serveraddr;serveraddr.sin_family = AF_INET;inet_pton(AF_INET, "192.168.139.133", &serveraddr.sin_addr.s_addr);serveraddr.sin_port = htons(9999);int ret = connect(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));if(ret == -1) {perror("connect");exit(-1);}// 3. 通信char recvBuf[1024];int i = 0;while(1) {sprintf(recvBuf, "data : %d\n", i++);// 给服务器端发送数据write(fd, recvBuf, strlen(recvBuf)+1);int len = read(fd, recvBuf, sizeof(recvBuf));if(len == -1) {perror("read");exit(-1);} else if(len > 0) {printf("recv server : %s\n", recvBuf);} else if(len == 0) {// 表示服务器端断开连接printf("server closed...");break;}sleep(1);}// 关闭连接close(fd);return 0;
}
服务端代码:
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>struct sockInfo {int fd; // 通信的文件描述符struct sockaddr_in addr;pthread_t tid; // 线程号
};struct sockInfo sockinfos[128];void * working(void * arg) {// 子线程和客户端通信 cfd 客户端的信息 线程号// 获取客户端的信息struct sockInfo * pinfo = (struct sockInfo *)arg;char cliIp[16];inet_ntop(AF_INET, &pinfo->addr.sin_addr.s_addr, cliIp, sizeof(cliIp));unsigned short cliPort = ntohs(pinfo->addr.sin_port);printf("client ip is : %s, prot is %d\n", cliIp, cliPort);// 接收客户端发来的数据char recvBuf[1024];while(1) {int len = read(pinfo->fd, &recvBuf, sizeof(recvBuf));if(len == -1) {perror("read");exit(-1);}else if(len > 0) {printf("recv client : %s\n", recvBuf);} else if(len == 0) {printf("client closed....\n");break;}write(pinfo->fd, recvBuf, strlen(recvBuf) + 1);}close(pinfo->fd);return NULL;
}int main() {// 创建socketint lfd = socket(PF_INET, SOCK_STREAM, 0);if(lfd == -1){perror("socket");exit(-1);}struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(9999);saddr.sin_addr.s_addr = INADDR_ANY;// 绑定int ret = bind(lfd,(struct sockaddr *)&saddr, sizeof(saddr));if(ret == -1) {perror("bind");exit(-1);}// 监听ret = listen(lfd, 128);if(ret == -1) {perror("listen");exit(-1);}// 初始化数据int max = sizeof(sockinfos) / sizeof(sockinfos[0]);for(int i = 0; i < max; i++) {bzero(&sockinfos[i], sizeof(sockinfos[i]));sockinfos[i].fd = -1;//表示该文件描述符可用sockinfos[i].tid = -1;}// 循环等待客户端连接,一旦一个客户端连接进来,就创建一个子线程进行通信while(1) {struct sockaddr_in cliaddr;int len = sizeof(cliaddr);// 接受连接int cfd = accept(lfd, (struct sockaddr*)&cliaddr, &len);struct sockInfo * pinfo;for(int i = 0; i < max; i++) {// 从这个数组中找到一个可以用的sockInfo元素if(sockinfos[i].fd == -1) {pinfo = &sockinfos[i];break;}if(i == max - 1) {sleep(1);i--;}}pinfo->fd = cfd;memcpy(&pinfo->addr, &cliaddr, len);// 创建子线程pthread_create(&pinfo->tid, NULL, working, pinfo);pthread_detach(pinfo->tid);}close(lfd);return 0;
}
相关文章:

【项目 计网7】4.20 多进程实现并发服务器 4.22 多线程实现并发服务器
文章目录 4.20 多进程实现并发服务器server_process.cclient.c4.22 多线程实现并发服务器客户端代码:服务端代码: 4.20 多进程实现并发服务器 要实现TCP通信服务器处理并发的任务,使用多线程或者多进程来解决。 思路: 1、一个父进…...

论文阅读_扩散模型_LDM
英文名称: High-Resolution Image Synthesis with Latent Diffusion Models 中文名称: 使用潜空间扩散模型合成高分辨率图像 地址: https://ieeexplore.ieee.org/document/9878449/ 代码: https://github.com/CompVis/latent-diffusion 作者:Robin Rombach 日期: 20…...

LeetCode——回溯篇(二)
刷题顺序及思路来源于代码随想录,网站地址:https://programmercarl.com 目录 131. 分割回文串 93. 复原 IP 地址 78. 子集 90. 子集 II 491. 递增子序列 131. 分割回文串 给你一个字符串 s,请你将 s 分割成一些子串,使每个…...

RabbitMQ工作模式-发布订阅模式
Publish/Subscribe(发布订阅模式) 官方文档: https://www.rabbitmq.com/tutorials/tutorial-three-python.html 使用fanout类型类型的交换器,routingKey忽略。每个消费者定义生成一个队列关绑定到同一个Exchange,每个…...

JDK源码解析-Object
1. Object类 所有类的基类——java.lang.Object Object 类是所有类的基类,当一个类没有直接继承某个类时,默认继承Object类Object 类属于 java.lang 包,此包下的所有类在使用时无需手动导入,系统会在程序编译期间自动导入。 思…...

pinia——添加插件——基础积累
问题:是否给pinia添加过插件?具体添加的方式是什么? 在pinia中,我们可以为仓库添加插件,通过添加插件能够扩展以下的内容: 为 store 添加新的属性 定义 store 时增加新的选项 为 store 增加新的方法 包装现…...

软件国产化之殇
今天又看到这么一个帖子讨论一款国产化软件,属实给我震撼到了。 对于国产化产品,一直主打的都是”自研“,难道是我对”自研“这个词的理解有误? 做一个产品,别人开源了,你拿过来使用,你可以说…...

SQLyog问题处理集合
sqlyog 问题处理 1. 错误号码:1049错误: 数据库命令参数参考:数据库命令地址 检查数据库是否存在检查创建的数据库名称 与 要进行连接的数据库名称是否一致; 2. 错误号码:1819错误: MySQL授予远程连接权限时出现: …...

JavaSE【继承和多态】(1)(重点:初始化、pretected封装、组合)
一、继承 继承 (inheritance) 机制 :是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性 的基础上进行扩展,增加新功能 ,这样产生新的类,称 派生类 。 继承呈现了面向对象程序设计的层次结…...

无涯教程-Android Studio函数
第1步-系统要求 您将很高兴知道您可以在以下两种操作系统之一上开始Android应用程序的开发- MicrosoftWindows10/8/7/Vista/2003(32或64位)MacOSX10.8.5或更高版本,最高10.9(小牛) GNOME或KDE桌面 第二点是,开发Android应用程序所需的所有工具都是开源的,可以从Web上下载。以…...

CentOS8安装mysql8.0.24
一、下载mysql安装包并解压 执行以下命令: # 创建mysql安装目录 mkdir /usr/local/mysql # 进入mysql安装目录 cd /usr/local/mysql/ # 下载mysql-8.0.24 wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.24-linux-glibc2.12-x86_64.tar.xz # 解压…...

Quasi-eccentricity Error Modeling and Compensation in Vision Metrology
论文:Quasi-eccentricity Error Modeling and Compensation in Vision Metrology 中文:视觉计量中准偏心误差建模与补偿 论文地址:Sci-Hub | Quasi-eccentricity error modeling and compensation in vision metrology. Measurement Scienc…...

ai智能电话机器人是人类的助手和朋友
一直以来,人工智能都是人们关注的热门话题。在以前,说到人工智能,第一想到的是“机器人”,随着人工智能的普及,AI已经渗透到我们生活的每一个角落。现在,说起人工智能,可能会想到“无人驾驶、无…...

应用TortoiseSVN的SubWCRev管理VisualStudio C#项目编译版本号
首先要安装 TortoiseSVN, 并确保TortoiseSVN的bin目录被加入到系统环境变量Path中。 1、拷贝Porperties目录下的文件AssemblyInfo.cs生成副本AssemblyInfo.template, 作为版本管理的模板文件。 2、修改模板文件中的想要管理的版本号信息 // [assembly: AssemblyVersion(&quo…...

【八股】2023秋招八股复习笔记5(计算机网络-CN)
文章目录 八股目录目录1、应用层 & HTTP一些http题HTTPS 加密原理(问过)HTTP/1.1 新特性HTTP/2.0 与 RPC(问过)GET 和 POST 比较 2、传输层 & TCPTCP三次握手 & 四次挥手(问过)为什么每次TCP 连…...

【C++】SLT——Vector详解
本片要分享的是关于STL中Vector的内容,Vector的内容于string非常相似,只要会使用string那么学习Vector时会非常流畅。 目录 1.vector介绍 2.vector的简单实用 2.1.简单的无参构造 编辑2.2.简单带参构造 2.3.迭代器区间初始化 2.4.vector的遍历 …...

企业网络安全:威胁情报解决方案
什么是威胁情报 威胁情报是网络安全的关键组成部分,可为潜在的恶意来源提供有价值的见解,这些知识可帮助组织主动识别和防止网络攻击,通过利用 STIX/TAXII 等威胁源,组织可以检测其网络中的潜在攻击,从而促进快速检测…...

为什么2G、3G、4G成功了,5G却?
你可能已经多年来一直听到关于闪电般的5G的炒作。虽然新的无线网络在美国仍然没有普及,但5G正在波士顿和西雅图到达拉斯和堪萨斯城等城市慢慢出现。随着连接速度的加快,用户的安全性和隐私保护将增加,因为无线行业试图改善3G和4G的防御。但是…...

C语言每日一练------Day(10)
本专栏为c语言练习专栏,适合刚刚学完c语言的初学者。本专栏每天会不定时更新,通过每天练习,进一步对c语言的重难点知识进行更深入的学习。 今日练习题关键字:自除数 除自身以外数组的乘积 💓博主csdn个人主页ÿ…...
发力服务业务,龙湖集团半程领跑赢在“智慧”
成立三十载,龙湖集团一直是房地产行业“特立独行”的存在。 一方面,龙湖在对外战略方面长期量入为出,从不背上过重的“包袱”。 不久前,一则消息引发市场关注:龙湖集团提前偿还17亿元债务,已基本全部还清…...

Kubernetes(七)修改 pod 网络(flannel 插件)
一、 提示 需要重启服务器 操作之前备份 k8s 中所有资源的 yaml 文件 如下是备份脚本,仅供参考 # 创建备份目录 test -d $3 || mkdir $3 # $1 命名空间 # $2 资源名称: sts deploy configMap svc 等 # $3 资源备份存放的目录名称for app in kubec…...

测试平台metersphere
metersphere可以做接口测试、UI测试、性能测试。 metersphere接口测试底层是jmeter,可以做API管理,快捷调试,接口用例管理,接口自动化场景执行一键选取用例范围,生成测试报告。 会用jmeter,metersphere会…...

论文笔记: One Fits All:Power General Time Series Analysis by Pretrained LM
1 intro 时间序列领域预训练模型/foundation 模型的研究还不是很多 主要挑战是缺乏大量的数据来训练用于时间序列分析的基础模型——>论文利用预训练的语言模型进行通用的时间序列分析 为各种时间序列任务提供了一个统一的框架 论文还调查了为什么从语言领域预训练的Transf…...

记录--怎么实现一个3d翻书效果
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 本篇主要讨论以下两种翻书动画的实现: 第一种是整页翻转的效果: 这种整页翻转的效果主要是做rotateY的动画,并结合一些CSS的3d属性实现。 第二种折线翻转的效果&…...

(数字图像处理MATLAB+Python)第十一章图像描述与分析-第一节、二节:图像描述概述和特征点
文章目录 一:图像描述概述(1)图像描述(2)描述子 二:特征点(1)Moravec角点检测A:原理B:程序 (2)Harris角点检测A:原理B&…...

SSM框架的学习与应用(Spring + Spring MVC + MyBatis)-Java EE企业级应用开发学习记录(第五天)MyBatis的注解开发
SSM框架的学习与应用(Spring Spring MVC MyBatis)-Java EE企业级应用开发学习记录(第五天)MyBatis的注解开发 昨天我们深入学习了MyBatis多表之间的关联映射,了解掌握了一对一关联映射,一对多关联映射,嵌套查询方…...

VBA技术资料MF48:VBA_在Excel中将列号与字母转换
【分享成果,随喜正能量】除非自己的认知获得了改变和刷新,否则,人们常说的“顺应自己的内心”,顺的不过是一颗旧心,一颗惯性的,充满了各种习性的套路之心。与“顺应自己的内心”恰恰相反,人要用…...

LeetCode-160. 相交链表
这是一道真的非常巧妙的题,题解思路如下: 如果让他们尾端队齐,那么从后面遍历就会很快找到第一个相交的点。但是逆序很麻烦。 于是有一个巧妙的思路诞生了,如果让短的先走完自己的再走长的,长的走完走短的,…...

微信小程序如何实现页面传参和页面传递多个参数
前言 只要你的小程序超过一个页面那么可能会需要涉及到页面参数的传递,下面我总结了 4 种页面方法。 下面时多个参数页面传参的方式 let loveJSON.stringify(this.data.totle);let youJSON.stringify(this.data.totleId)let csdnJSON.stringify(this.data.totleP…...

ChatGPT⼊门到精通(3):ChatGPT 原理
OpenAI在2022年11⽉份发布ChatGPT,强⼤的⽂字对话、创意写作能⼒,全球掀起了⼀ 波AI浪潮。本⽂对ChatGPT的技术原理、厉害之处、可能的落地⽅向等⽅⾯进⾏了全⾯ 的解析,看完后会对ChatGPT有更深⼊的了解。 ⼀、前⾔ 2022年11⽉30⽇&#x…...