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

TCP服务器实现—多进程版,多线程版,线程池版

目录

前言

1.存在的问题

2.多进程版

3.多线程版

4.线程池版

总结


前言

        在上一篇文章中使用TCP协议实现了一个简单的服务器,可以用来服务端和客户端通信,但是之前的服务器存在一个问题,就是当有多个客户端连接服务器的时候,服务器只能和一个客户端通信,其它的客户端是无法通信的,这是为什么呢?有该如何解决呢?将在这篇文章中为大家介绍

1.存在的问题

如图所示:

 为什么会存在这样的问题呢?

如上图所示,之前我们实现的服务器是单进程版的,所以当第一次和客户端建立连接完成之后,就死循环处理读取信息的逻辑了,所以就无法再和新的客户端建立连接了 。找到问题之后,很明显解决方式就是将建立连接和通信分开执行,此时我们就可以使用多进程和多线程来解决了,下面我们就具体来实现以下如何使用多进程和多线程。

2.多进程版

实现思路:与客户端建立连接完成,fork创建子进程,让父进程继续建立连接,让子进程实现后续的数据通信。

这样实现存在的问题:当父进程创建完子进程之后,需要使用waitpid回收子进程的资源,否则子进程就会变为僵尸进程,导致资源泄漏,但是使用waitpid回收子进程资源,程序变为串行化执行了,就无法实现之前的需求,让父进程负责建立连接,子进程负责数据通信了。

解决方式有两种:

1.fork创建子进程,在子进程内部再fork创建子进程,然后让父进程直接退出,此时之前的子进程作为父进程退出,新创建的子进程就变为孤儿进程被操作系统领养,并不会造成资源泄漏,并且让该子进程负责通信

2.因为子进程退出之后操作系统会发送一个SIGCHLD信号,所以可以使用signal函数捕捉SIGCHLD信号,将默认处理动作设置为SIG_IGN,在这个默认动作里会回收子进程的资源,并不会造成资源泄漏,并且让该子进程负责通信

思路1代码:

pid_t id = fork();
if(id == 0)//child
{close(_sock);if(fork() > 0)exit(0);serviceIO(sock);close(sock);exit(0);
}
close(sock);
waitpid(id,nullptr,0);

思路2代码:

signal(SIGCHLD,SIG_IGN);
if(id == 0)//child
{// 子进程会继承父进程的文件描述符表,当子进程不需要时进行关闭,// 防止子进程文件描述符资源泄露close(_sock);serviceIO(sock);close(sock);exit(0);
}

运行截图:

[myl@VM-8-12-centos tcp]$ ./tcpServer 8080
create socket success
bind socket success
listen socket success
accept a new link success
sock: 4
accept a new link success
sock: 4
recvice message: 你好,我是客户端1
recvice message: 你好,我是客户端2

此时就实现了一个客户端可以被多个服务端连接并且实现通信。

3.多线程版

说明:相比于多进程,多线程的创建和销毁对操作系统是更轻量的,消耗的资源也是更少的,所以实现数据通信可以采用多线程的方式,让主线程负责建立,让从线程负责数据通信

代码实现:

class TcpServerData
{
public:TcpServerData(TcpServer* self,int sock):_self(self),_sock(sock) {}
public:TcpServer* _self;int _sock;
};
cout << "我是主线程" << endl;
pthread_t tid;
TcpServerData* tsd = new TcpServerData(this,sock);
pthread_create(&tid,nullptr,start_routine,tsd);//因为是类内成员函数,必须包含this指针,但是start_routine作为参数是没有this指针的
//所以start_routine函数必须加上static,静态成员方法是不能访问类内成员的,所以参数传递this
//调用serviceIO,但是serviceIO函数需要传递参数sock,所以可以封装一个结构体,在结构体中包含成员
//属性sock和this
static void* start_routine(void* args) {
//设置与主线程分离,此时主线程不需要等待从线程退出了,而是继续建立连接
cout << "我是从线程" << endl;
pthread_detach(pthread_self());
TcpServerData* t = static_cast<TcpServerData*>(args);
t->_self->serviceIO(t->_sock);
close(t->_sock);
delete t;
return nullptr;

运行截图:

[myl@VM-8-12-centos tcp]$ ./tcpServer 8080
create socket success
bind socket success
listen socket success
accept a new link success
sock: 4
我是主线程
我是从线程
recvice message: 你好,我是客户端1
accept a new link success
sock: 5
我是主线程
我是从线程
recvice message: 你好,我是客户端2

4.线程池版

说明:线程池版的实现思路是基于多线程,虽然多线程创建和销毁的消耗比多进程的低,但是为了更进一步提升效率,可以预先创建好一批线程,主线程负责建立连接获取任务,然后将任务加入到队列中,让预先创建好的线程从队列中获取任务,然后处理获取到的任务。

代码实现:

void start()
{//线程池初始化:预先创建好一批线程:ThreadPool<Task>::getInstance()->run();for (;;){// 建立连接:struct sockaddr_in peer;socklen_t len = sizeof(peer);int sock = accept(_sock, (struct sockaddr *)&peer, &len); if (sock < 0){logMessage(ERROR, "accept error, next");continue;}logMessage(NORMAL, "accept a new link success");std::cout << "sock: " << sock << std::endl;//未来通信全部用sock,面向字节流的,后续全部都是文件操作:ThreadPool<Task>::getInstance()->push(Task(sock,serviceIO));}
}

运行截图:

[myl@VM-8-12-centos tcp]$ ./tcpServer 8080
create socket success
bind socket success
listen socket success
thread-1 start ...
thread-2 start ...
thread-3 start ...
thread-4 start ...
thread-5 start ...
thread-6 start ...
thread-7 start ...
thread-8 start ...
thread-9 start ...
thread-10 start ...
accept a new link success
sock: 4
accept a new link success
sock: 5
recv message: 你好,我是客户端1
recv message: 你好,我是客户端2
注:关于线程池详细的设计与实现可以观看线程池这篇文章,里面有相信的代码实现

总结

        以上就是关于TCP服务器实现多进程版,多线程版,线程池版的详细介绍,可以通过这篇文章发现之前在系统中学习的知识在网络中全部结合起来了,今天的介绍就到这里了,感谢大家的阅读,我们下次再见!

相关文章:

TCP服务器实现—多进程版,多线程版,线程池版

目录 前言 1.存在的问题 2.多进程版 3.多线程版 4.线程池版 总结 前言 在上一篇文章中使用TCP协议实现了一个简单的服务器&#xff0c;可以用来服务端和客户端通信&#xff0c;但是之前的服务器存在一个问题&#xff0c;就是当有多个客户端连接服务器的时候&#xff0c;服…...

Nginx 配置文件的完整指南 (二)

文章目录 四、反向代理配置4.1 proxy_pass效果1—路径重写效果2—转发到其他服务器 4.2 proxy_pass使用规则4.3 proxy_set_header4.3.1 修改请求协议 五、负载均衡配置5.1 upstream5.2 server5.3 负载均衡策略5.3.1 轮询5.3.2 加权轮询5.3.3 最少连接5.3.3 ip_hash&#xff1a;…...

AI夏令营第三期 - 基于论文摘要的文本分类与关键词抽取挑战赛笔记

赛题&#xff1a;基于论文摘要的文本分类与关键词抽取 背景&#xff1a;高效的从海量医学文献中提取疾病诊断和治疗关键信息 任务&#xff1a;通过论文摘要判断论文是否为医学文献 样例 数据集&#xff1a;csv文件&#xff0c;字段&#xff1a;标题、作者、摘要、关键词 评价指…...

使用qsqlmysql操作mysql提示Driver not loaded

环境: win10 IDE: qt creator 编译器: mingw32 这里简单的记录下。我遇到的情况是在IDE使用debug和release程序都是运行正常&#xff0c;但是当我编译成发布版本之后。老是提示Driver not load。 这就很奇诡了。 回顾了下编译的时候是需要在使用qt先编译下libqsqlmysql.dll的…...

Java云原生框架Quarkus初探

Java云原生框架Quarkus初探 Quarkus 介绍 Quarkus 是一个云原生&#xff0c;容器优先的Java应用框架&#xff0c;它号称是超音速和亚原子的框架&#xff0c;主要特点是构建速度、启动速度快和占用资源少等特点。它为OpenJDK HotSpot和GraalVM量身定制&#xff0c; 根据Java库和…...

ElasticSearch相关概念

文章目录 前提倒排索引MySQL、ES的区别和关联IK分词器索引库mapping属性索引库的crud 文档的crudRestClientDSL查询DSL 查询种类DSL query 基本语法 搜索结构处理排序分页高亮RestClient 前提 开源的搜索引擎&#xff0c;从海量数据中快速找到需要的内容。&#xff08;分词检索…...

微服务实战项目-学成在线-项目部署

微服务实战项目-学成在线-项目部署 1 什么是DevOps 一个软件的生命周期包括&#xff1a;需求分析阶、设计、开发、测试、上线、维护、升级、废弃。 通过示例说明如下&#xff1a; 1、产品人员进行需求分析 2、设计人员进行软件架构设计和模块设计。 3、每个模块的开发人员…...

封装form表单

目录 1. 源码 2. 其他页面引用 ps&#xff1a;请看完看明白再复用 1. 源码 <template><div style"width: 100%; height: 100%" class"form-condition"><!-- 普通表单 --><el-card shadow"hover" class"cardheigh…...

程序员如何利用公网远程访问查询本地硬盘【内网穿透】

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《高效编程技巧》《cpolar》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 公网远程访问本地硬盘文件【内网穿透】 文章目录 公网远程访问本地硬盘文件【内网穿透】前言1. 下载cpolar和Everything软件1.…...

算法|Day42 动态规划10

LeetCode 121.买卖股票的最佳时机 题目链接&#xff1a;https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/description/ 题目描述&#xff1a;给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天…...

vmalert集成钉钉告警

vmalert通过在alert.rules中配置告警规则实现告警&#xff0c;告警规则语法与Prometheus兼容&#xff0c;依赖Alertmanager与prometheus-webhook-dingtalk实现钉钉告警&#xff0c;以下步骤&#xff1a; 1、构建vmalert 从源代码构建vmalert&#xff1a; git clone https://…...

深入解析 MyBatis 中的 <foreach> 标签:优雅处理批量操作与动态 SQL

在当今的Java应用程序开发中&#xff0c;数据库操作是一个不可或缺的部分。MyBatis作为一款颇受欢迎的持久层框架&#xff0c;为我们提供了一种优雅而高效的方式来管理数据库操作。在MyBatis的众多特性中&#xff0c;<foreach>标签无疑是一个强大的工具&#xff0c;它使得…...

LeGO-Loam代码解析(二)--- Lego-LOAM的地面点分离、聚类、两步优化方法

1 地面点分离剔除方法 1.1 数学推导 LeGO-LOAM 中前端改进中很重要的一点就是充分利用了地面点,那首先自然是提取 对地面点的提取。 如上图,相邻的两个扫描线束的同一列打在地面上如 点所示,他们的垂直高度差 &#xff0c;水平距离差 &#xff0c;计算垂直高度差和水平高度差…...

程序员如何利用公网打造低成本轻量化的搜索和下载平台【内网穿透】

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《高效编程技巧》《cpolar》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 公网远程访问本地硬盘文件【内网穿透】 文章目录 公网远程访问本地硬盘文件【内网穿透】前言1. 下载cpolar和Everything软件1.…...

构建可远程访问的企业内部论坛

文章目录 前言1.cpolar、PHPStudy2.Discuz3.打开PHPStudy&#xff0c;安装网页论坛所需软件4.进行网页运行环境的构建5.运行Discuz网页程序6.使用cpolar建立穿透内网的数据隧道&#xff0c;发布到公网7.对云端保留的空白数据隧道进行配置8.Discuz论坛搭建完毕 前言 企业在发展…...

2023河南萌新联赛第(六)场:河南理工大学-C 旅游

2023河南萌新联赛第&#xff08;六&#xff09;场&#xff1a;河南理工大学 https://ac.nowcoder.com/acm/contest/63602/C 文章目录 2023河南萌新联赛第&#xff08;六&#xff09;场&#xff1a;河南理工大学题意解题思路代码 题意 小C喜欢旅游&#xff0c;现在他要去DSH旅…...

C语言 常用工具型API ----------strchr()

函数原型 char *strchr(const char *str, int c) 参数 str-- 要被检索的 C 字符串。 c-- 在 str 中要搜索的字符。 功能 在参数str所指向的字符串中搜索第一次出现字符c&#xff08;一个无符号字符&#xff09;的位置 头文件 #include <string.h> 返回值 返回一…...

建造者模式的理论与实现

本文实践代码仓库&#xff1a;https://github.com/goSilver/my_practice 文章目录 一、定义二、作用三、实现四、总结 一、定义 建造者模式是一种创建复杂对象的设计模式。它将一个复杂对象的构建过程分解为多个简单的步骤&#xff0c;并且允许按照特定的顺序来构建对象。通过…...

非计算机科班如何顺利转码进入计算机领域?

文章目录 如何规划才能实现转码&#xff1f;计算机岗位发展前景&#xff1f;现阶段转码 总结 &#x1f389;欢迎来到Java学习路线专栏~探索非计算机科班如何顺利转码进入计算机领域 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客&#x1f3…...

【C++类和对象】类有哪些默认成员函数呢?(下)

文章目录 一、类的6个默认成员函数二、日期类的实现2.1 运算符重载部分2.2 日期之间的运算2.3 整体代码1.Date.h部分2. Date.cpp部分 三. const成员函数四. 取地址及const取地址操作符重载扩展内容 总结 ヾ(๑╹◡╹)&#xff89;" 人总要为过去的懒惰而付出代价ヾ(๑╹◡…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器&#xff1a;Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...