自学Linux系统软件编程第八天

并发服务器: 服务器在同一时刻可以响应多个客户端的请求。

UDP:无连接

单循环服务器:服务器同一时刻只能响应一个客户端的请求。

TCP:有连接

构建TCP并发服务器: 让TCP服务端具备同时响应多个客户端的能力。

方法一:多进程

资源开销大,同资源平台下,并发量小。

--------------------------------------------------------------实现-------------------------------------------------------------

#include <stdio.h>
#include "head.h"#define LISTEN_CLI__MAX_CNT 1024int init_tcp_ser(const char *ip, unsigned short port)
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("fail socket");return -1;}struct sockaddr_in ser;ser.sin_family = AF_INET;ser.sin_port = htons(port);ser.sin_addr.s_addr = inet_addr(ip);int ret = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser));if (ret < 0){perror("fail bind");return -1;}ret = listen(sockfd, LISTEN_CLI__MAX_CNT);if (ret < 0){perror("fail listen");return -1;}return sockfd;
}void handler(int signum)
{wait(NULL);
}int main(int argc, const char *argv[])
{struct sockaddr_in cli;socklen_t clilen = sizeof(cli);signal(SIGCHLD, handler);int sockfd = init_tcp_ser("192.168.1.179", 50000);if (sockfd < 0){return -1;}while (1){int connfd = accept(sockfd, (struct sockaddr *)&cli, &clilen);if (connfd < 0){perror("fail accept");return -1;}pid_t pid = fork();if (pid > 0){}else if (0 == pid){char buff[1024] = {0};while (1){memset(buff, 0, sizeof(buff));size_t size = recv(connfd, buff, sizeof(buff), 0);if (size < 0){perror("fail recv");exit(1);}else if (0 == size) // closed{break;}printf("[%s : %d][%ld] %s\n", inet_ntoa(cli.sin_addr), ntohs(cli.sin_port), size, buff);strcat(buff, "--->ok");size = send(connfd, buff, strlen(buff), 0);if (size < 0){perror("fail send");exit(1);}}exit(0);}else{perror("fail fork");return -1;}}return 0;
}

子进程结束会隐含一个SIGCHLD信号,对该信号进行注册,然后跳转到该函数进行操作。

方法二:多线程

资源消耗相比多进程的较小

--------------------------------------------------------------实现-------------------------------------------------------------

#include <stdio.h>
#include "head.h"#define LISTEN_CLI__MAX_CNT 1024int init_tcp_ser(const char *ip, unsigned short port)
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("fail socket");return -1;}struct sockaddr_in ser;ser.sin_family = AF_INET;ser.sin_port = htons(port);ser.sin_addr.s_addr = inet_addr(ip);int ret = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser));if (ret < 0){perror("fail bind");return -1;}ret = listen(sockfd, LISTEN_CLI__MAX_CNT);if (ret < 0){perror("fail listen");return -1;}return sockfd;
}void *do_communicate(void *arg)
{char buff[1024] = {0};int connfd = *(int *)arg;while (1){memset(buff, 0, sizeof(buff));size_t size = recv(connfd, buff, sizeof(buff), 0);if (size < 0){perror("fail recv");return NULL;}else if (0 == size){break;}printf("%s\n", buff);strcat(buff, "---->ok");size = send(connfd, buff, strlen(buff), 0);if (size < 0){perror("fail send");return NULL;}}return NULL;
}int main(int argc, const char *argv[])
{struct sockaddr_in cli;pthread_t tid;socklen_t clilen = sizeof(cli);int sockfd = init_tcp_ser("192.168.1.179", 50000);if (sockfd < 0){return -1;}while (1){int connfd = accept(sockfd, (struct sockaddr *)&cli, &clilen);if (connfd < 0){perror("fail accept");return -1;}pthread_create(&tid, NULL, do_communicate, &connfd);pthread_detach(tid);}return 0;
}

 方法三:线程池

提前预创建大量线程,避免任务执行过程中创建线程的耗时。

方法四:IO多路复用(转接)

在不创建新的进程和线程的情况下,可以在一个进程中同时监测多个IO

===============“黑心饭店老板和一个牛马服务员的悲惨故事”=========================

#include <stdio.h>
#include "head.h"#define LISTEN_CLI__MAX_CNT 1024int init_tcp_ser(const char *ip, unsigned short port)
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("fail socket");return -1;}struct sockaddr_in ser;ser.sin_family = AF_INET;ser.sin_port = htons(port);ser.sin_addr.s_addr = inet_addr(ip);int ret = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser));if (ret < 0){perror("fail bind");return -1;}ret = listen(sockfd, LISTEN_CLI__MAX_CNT);if (ret < 0){perror("fail listen");return -1;}return sockfd;
}int main(int argc, const char *argv[])
{struct sockaddr_in cli;pthread_t tid;int maxfd = -1;char buff[1024] = {0};socklen_t clilen = sizeof(cli);int sockfd = init_tcp_ser("192.168.1.158", 50000);if (sockfd < 0){return -1;}fd_set tmpfds;fd_set rdfds;FD_ZERO(&rdfds);FD_SET(sockfd, &rdfds);maxfd = maxfd > sockfd ? maxfd : sockfd;while (1){tmpfds = rdfds;int cnt = select(maxfd+1, &tmpfds, NULL, NULL, NULL);if (cnt < 0){perror("fail select");return -1;}for (int i = 0; i <= maxfd; i++){if (FD_ISSET(i, &tmpfds)){if (i == sockfd){int connfd = accept(sockfd, (struct sockaddr *)&cli, &clilen);if (connfd < 0){perror("fail accept");continue;}FD_SET(connfd, &rdfds);maxfd = maxfd > connfd ? maxfd : connfd;printf("[%s : %d] online\n", inet_ntoa(cli.sin_addr), ntohs(cli.sin_port));}else{//connfdmemset(buff, 0, sizeof(buff));ssize_t size = recv(i, buff, sizeof(buff), 0);if (size < 0){perror("fail recv");FD_CLR(i, &rdfds);close(i);continue;}else if (0 == size){FD_CLR(i, &rdfds);close(i);continue;	}printf("%s\n", buff);strcat(buff, "----ok");size = send(i, buff, strlen(buff), 0);if (size < 0){perror("fail send");FD_CLR(i, &rdfds);close(i);continue;}}}}}return 0;
}

上述所用到的就是select函数:


/* According to POSIX.1-2001 */
#include <sys/select.h>/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);功能:阻塞等待IO事件,返回事件结果
参数:nfds:关注的最大文件描述符+1;readfds:文件描述符读事件的集合表writefds:文件描述符写事件的集合表exceptfds:其他事件表timeout:超时时间(如果不设置超时时间,则该位置为NULL)即select的等待时间
返回值:成功返回到达的文件描述符事件个数,失败返回-1,如果超时时间到达还没有IO事件时返回0void FD_CLR(int fd, fd_set *set);
int  FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);

实现多路复用的过程(select,poll,epoll)

1.创建文件描述符集合

2.将关注的文件描述符加入到集合

3.等待IO时间到达

4.根据不同的IO事件处理不同的任务

select的不足之处:

1.底层使用位图管理文件描述符,最多允许同时监测1024个文件描述符(有上限)

2.文件描述符集合在应用层创建需要实现应用层和内核层的反复拷贝。

3.需要应用层对集合表进行遍历,循环找到达的事件。

4.只能工作在水平触发模式(低速模式),不能工作在边沿触发模式(高速模式)。

QUESTION:

完成多线程时,代码写完线程的时候不知道怎么关闭线程,如果就放在while(1)里面,就会阻塞后面的进程,那该怎么解决呢,我就查询了一些资料,发现可以对线程进行分离,

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FusionInsight MRS云原生数据湖

FusionInsight MRS云原生数据湖 1、FusionInsight MRS概述2、FusionInsight MRS解决方案3、FusionInsight MRS优势4、FusionInsight MRS功能 1、FusionInsight MRS概述 1.1、数据湖概述 数据湖是一个集中式存储库&#xff0c;允许以任意规模存储所有结构化和非结构化数据。可以…

.NET 10首个预览版发布:重大改进与新特性概览!

前言 .NET 团队于2025年2月25日发布博文&#xff0c;宣布推出 .NET 10 首个预览版更新&#xff0c;重点改进.NET Runtime、SDK、Libraries 、C#、ASP.NET Core、Blazor 和.NET MAUI 等。 .NET 10介绍 .NET 10 是 .NET 9 的后继版本&#xff0c;将作为长期支持维护 &#xff…

HTTP 黑科技

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

C++20 模块:告别头文件,迎接现代化的模块系统

文章目录 引言一、C20模块简介1.1 传统头文件的局限性1.2 模块的出现 二、模块的基本概念2.1 模块声明2.2 模块接口单元2.3 模块实现单元 三、模块的优势3.1 编译时间大幅减少3.2 更好的依赖管理3.3 命名空间隔离 四、如何使用C20模块4.1 编译器支持4.2 示例项目4.3 编译和运行…

计算光学成像与光学计算概论

计算光学成像所涉及研究的内容非常广泛&#xff0c;虽然计算光学成像的研究内容是发散的&#xff0c;但目的都是一致的&#xff1a;如何让相机记录到客观实物更丰富的信息&#xff0c;延伸并扩展人眼的视觉感知。总的来说&#xff0c;计算光学成像现阶段已经取得了很多令人振奋…

安铂克科技 APPH 系列相位噪声分析仪:高性能测量的卓越之选

在当今的电子测量领域&#xff0c;对于信号源及各类设备的精确评估至关重要。安铂克科技的 APPH 系列相位噪声分析仪&#xff08;亦称作相噪仪、相位噪声测量仪、信号源分析仪&#xff09;&#xff0c;凭借其超凡的性能与全面的功能&#xff0c;成为众多工程师与科研人员的理想…

算法探秘:盛最多水的容器问题

目录 一、问题引入 二、示例剖析 三、暴力解法与困境 四、双指针法&#xff1a;优雅的解决方案 五、总结 一、问题引入 在算法的奇妙世界里&#xff0c;常常会遇到各种有趣又富有挑战性的问题&#xff0c;“盛最多水的容器”就是其中之一。想象一下&#xff0c;有一系…

QTday4

1:是进度条通过线程自己动起来 mythread.h #ifndef MYTHREAD_H #define MYTHREAD_H #include <QThread>class mythread : public QThread {Q_OBJECT public:mythread(QObject* parent nullptr); protected:virtual void run() override; private: signals:virtual voi…

PPT小黑第26套

对应大猫28 层次级别是错的&#xff0c;看着是十页&#xff0c;导入ppt之后四十多页 选中所有 红色蓝色黑色 文本选择标题&#xff1a;选择 -格式相似文本&#xff08;检查有没有漏选 漏选的话 按住ctrl 点下一个&#xff09; 要求新建幻灯片中不包含原素材中的任何格式&…

transformer架构解析{掩码,(自)注意力机制,多头(自)注意力机制}(含代码)-3

目录 前言 掩码张量 什么是掩码张量 掩码张量的作用 生成掩码张量实现 注意力机制 学习目标 注意力计算规则 注意力和自注意力 注意力机制 注意力机制计算规则的代码实现 多头注意力机制 学习目标 什么是多头注意力机制 多头注意力计算机制的作用 多头注意力机…

Spring编写单元测试的工具介绍:JUnit、Mockito、AssertJ

背景&#xff1a; 在Spring应用程序中&#xff0c;想要通过代码走查做好测试左移&#xff0c;单元测试是确保代码质量和功能正确性的关键。除了我们常用的TestNG外&#xff0c;本次介绍一下其他常见的单元测试工具: JUnit、Mockito、AssertJ&#xff0c;来提高我们做白盒测试的…

Kubermetes 部署mysql pod

步骤 1: 创建 PersistentVolume 和 PersistentVolumeClaim 首先为 MySQL 创建一个 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 来确保数据的持久性。 mysql-pv.yaml&#xff1a; apiVersion: v1 kind: PersistentVolume metadata:name: mysql-pv-volume spec:cap…

论坛社区基础版【项目测试报告】

文章目录 一、项目背景二、项目功能用户注册/登录帖子列表页发布帖子个人中心 三、测试工具和环境四、测试计划非功能测试用例功能测试用例部分人工手动测试截图web自动化测试测试用例代码框架 配置内容代码文件&#xff08;Utils.py&#xff09;注册页面代码文件&#xff08;R…

物联网IoT系列之MQTT协议基础知识

文章目录 物联网IoT系列之MQTT协议基础知识物联网IoT是什么&#xff1f;什么是MQTT&#xff1f;为什么说MQTT是适用于物联网的协议&#xff1f;MQTT工作原理核心组件核心机制 MQTT工作流程1. 建立连接2. 发布和订阅3. 消息确认4. 断开连接 MQTT工作流程图MQTT在物联网中的应用 …

如何面向DeepSeek编程,打造游戏开发工具集,提升工作效率

最近我在思考&#xff1a; 如何基于DeepSeek&#xff0c;来提升工作效率&#xff0c;构建高效游戏开发工作流。 方向有两个: A: 基于DeepSeek私有代码框架&#xff0c;让它完成项目代码的续写; B: 基于DeepSeek来创作一些工具&#xff0c;使用工具来提升效率&#xff0c;如…

云原生机密计算:构建基于可信执行环境的数据安全堡垒

引言&#xff1a;数据计算的最后一道防线 蚂蚁集团金融级机密计算平台承载日均20亿次敏感交易&#xff0c;密钥泄露风险降低99.97%。微软Azure DCsv3系列虚拟机实现SGX全内存加密性能损耗<15%&#xff0c;Google Anthos Confidential将跨云数据传输成本压缩45%。Gartner预测…

通用文件模型

一、通用文件模型 通常一个完整的Linux系统有数千到数百万个文件组成&#xff0c;文件中存储了程序、数据和各种信息。层次化的目录结构用于对文件进行编排和分组。 1.ReiserFS(新型的文件系统) -->Reiser4 它通过一种与众不同的方式----完全平衡树来容纳数据&#xff0c;包…

产品管理过程-思维导图

产品管理过程 1. 市场调研 与用户交流与直接面对客户的一线同事如销售、客服、技术支持等交流市场研究报告分析竞争对手分析用户数据分析 2. 需求管理 需求来源管理 市场需求内部需求运营需求战略需求其它需求 需求版本管理 需求分配管理 需求跟踪管理 3. 产品规划 市…

EtherNet/IP转Modbus解析基于网关模块的罗克韦尔PLC与Modbus上位机协议转换通讯案例

在工业自动化控制系统中&#xff0c;常常会遇到不同品牌和通信协议的设备需要协同工作的情况。本案例中&#xff0c;客户现场采用了 AB PLC&#xff0c;但需要控制的变频器仅支持 Modbus 协议。为了实现 AB PLC 对变频器的有效控制与监控&#xff0c;引入了捷米特 JM-EIP-RTU 网…

【进程和线程】(面试高频考点)

【进程和线程】 前言 在计算机编程领域&#xff0c;并发编程是一项至关重要的技术&#xff0c;而进程和线程正是实现并发编程的核心概念。为了让大家更直观地理解并发编程的作用&#xff0c;我们先来看一个简单的生活例子。 想象一下&#xff0c;现在有一大份美味的饭菜&…