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

服务器搭建(TCP套接字)-fork版(服务端)

    基础版的服务端虽然基本实现了服务器的基本功能,但是如果客户端的并发量比较大的话,服务端的压力和性能就会大打折扣,为了提升服务端的并发性能,可以通过fork子进程的方式,为每一个连接成功的客户端fork一个子进程,这样既达到了并发的要求,还能达到客户端隔离的效果。

一、fork

1.1、头文件

#include <sys/types.h>
#include <unistd.h>

1.2、原型

pid_t fork(void);

fork() 是一个系统调用函数,用于在 Unix-like 操作系统中创建一个新的进程。它会复制当前进程(称为父进程),并在新的进程(称为子进程)中继续执行。

fork() 函数返回的是一个 pid_t 类型的值,其含义如下:

  • 在父进程中,fork() 返回新创建的子进程的进程 ID(PID)。
  • 在子进程中,fork() 返回 0。
  • 如果创建子进程失败,fork() 返回 -1。

    fork() 函数在创建子进程时会返回两次,这是因为它是一个复制当前进程的系统调用。具体来说,fork() 函数会创建一个新的进程(子进程),并将父进程的所有内容(包括代码、数据、堆栈等)复制到子进程中。

第一次返回:

  • 父进程中,fork() 返回新创建的子进程的进程 ID(PID)。
  • 如果创建子进程失败,fork() 返回 -1。

第二次返回:

  • 子进程中,fork() 返回 0。

通过这两次返回,父进程和子进程可以根据不同的返回值采取不同的逻辑分支。

在父进程中,可以根据返回的子进程 PID 做一些与子进程相关的操作,如记录子进程的 PID、等待子进程的终止等。

在子进程中,由于 fork() 返回的是 0,可以根据此特性来区分自己是子进程,从而执行特定的子进程代码逻辑。

需要注意的是,父进程和子进程会继续执行 fork() 调用之后的代码,并且它们是在不同的进程上下文中运行的,拥有各自独立的内存空间和资源。因此,在使用 fork() 创建子进程时,通常需要在父子进程中进行不同的处理,以避免竞态条件和不必要的资源共享问题。

1.3、代码实现

#include <iostream>
//socket
#include <sys/types.h>
#include <sys/socket.h>
//close
#include <unistd.h>
//exit
#include <stdlib.h>
//perror
#include <stdio.h>
//memset
#include <string.h>
//htons
#include <arpa/inet.h>#define PORT 8596
#define MESSAGE_SIZE 1024int main(){int ret=-1;int socket_fd=-1;int accept_fd=-1;int backlog=10;int flag=1;int pid;struct sockaddr_in local_addr,remote_addr;//create socketsocket_fd=socket(AF_INET,SOCK_STREAM,0);if(socket_fd == -1){perror("create socket error");exit(1);}//set option of socketret = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));if ( ret == -1 ){perror("setsockopt error");}//set socket addresslocal_addr.sin_family=AF_INET;local_addr.sin_port=htons(PORT);local_addr.sin_addr.s_addr=INADDR_ANY;bzero(&(local_addr.sin_zero),8);//bind socketret=bind(socket_fd, (struct sockaddr *)&local_addr,sizeof(struct sockaddr_in));if(ret == -1){perror("bind socket error");exit(1);}ret=listen(socket_fd, backlog);if(ret ==-1){perror("listen error");exit(1);}//loop to accept clientfor(;;){socklen_t addrlen = sizeof(remote_addr);accept_fd=accept(socket_fd,( struct sockaddr *)&remote_addr, &addrlen);pid=fork();//子进程if(pid==0){char in_buf[MESSAGE_SIZE]={0,};for(;;){memset(in_buf,0,MESSAGE_SIZE);//read dataret =recv(accept_fd, (void*)in_buf, MESSAGE_SIZE, 0);pid_t currentID = getpid();std::cout << "Current Process ID: " << currentID << std::endl;if(ret ==0){break;}printf("receive data:%s\n",in_buf);send(accept_fd, (void *)in_buf, MESSAGE_SIZE, 0);}printf("close client connection......");close(accept_fd);}}if(pid !=0){printf("quit server....");close(socket_fd);}return 0;
}

1.4、实现效果

1.4.1、客户端1

连接成功,并成功收发数据

1.4.2、服务端接收客户端1

在这里插入图片描述

1.4.3、客户端2

在这里插入图片描述

1.4.4、服务端接收客户端2

在这里插入图片描述
可以看到,服务端对于两个客户端的处理是在不同的子进程中进行的。

使用 fork() 函数创建子进程的服务器有以下优点和缺点:

优点:

  • 简单易用:使用 fork() 函数创建子进程的服务器相对简单,不需要使用复杂的多线程或多进程编程模型。通过复制父进程的内存空间,子进程可以独立运行,处理客户端请求。
  • 高并发处理:每个客户端连接都可以创建一个独立的子进程,这样服务器能够同时处理多个客户端请求,实现高并发性能。
  • 数据共享:父进程和子进程共享文件描述符,可以轻松共享一些资源和状态信息,例如打开的文件、缓冲区等。
  • 可靠性:由于每个子进程是独立运行的,一个子进程的崩溃或异常不会影响其他子进程或主服务器进程。

缺点:

  • 内存开销:每个子进程都需要复制父进程的内存空间,因此在大规模并发的情况下,服务器的内存开销会比较大。
  • 进程切换开销:由于每个客户端连接都需要创建子进程,因此涉及到进程之间的切换开销,包括上下文切换和进程间通信开销,这可能对服务器性能产生一定的影响。
  • 可伸缩性:由于每个客户端连接都需要创建子进程,服务器的可伸缩性可能受到限制。在大规模并发情况下,为每个连接创建子进程可能会导致系统资源耗尽。
    进程间通信复杂性:如果子进程之间需要进行通信或共享数据,就需要使用进程间通信(IPC)机制,如管道、共享内存等。这增加了编程的复杂性。

    综上所述,使用 fork() 函数创建子进程的服务器适用于简单的并发场景和较小规模的应用,但在大规模高并发、资源消耗较大或需要更高可伸缩性的情况下,可能需要考虑其他并发模型,如多线程或事件驱动模型。

相关文章:

服务器搭建(TCP套接字)-fork版(服务端)

基础版的服务端虽然基本实现了服务器的基本功能&#xff0c;但是如果客户端的并发量比较大的话&#xff0c;服务端的压力和性能就会大打折扣,为了提升服务端的并发性能&#xff0c;可以通过fork子进程的方式&#xff0c;为每一个连接成功的客户端fork一个子进程&#xff0c;这样…...

缺失的第一个正数:高效解法与技术

缺失的第一个正数&#xff1a;高效解法与技术 背景 在计算机编程中&#xff0c;有时候需要寻找一个未排序整数数组中没有出现的最小的正整数。这篇技术博客将详细讨论这个问题&#xff0c;并提供一个时间复杂度为 O(n) 且只使用常数级别额外空间的解决方案。 问题描述 leet…...

常用的辅助网站(持续更新)

标题 一、uni-app方向二、H5方向 一、uni-app方向 1、uni-app官网 地址&#xff1a;https://uniapp.dcloud.net.cn/ 2、香蕉云编 地址&#xff1a;https://www.yunedit.com/ 描述&#xff1a;一般用来配置ios证书或安卓证书、上传ios包至商店 3、uView 地址&#xff1a;http…...

LeetCode 75 - 01 : 最小面积矩形

type pair struct{x, y int }func minAreaRect(points [][]int)int{mp : map[pair]struct{}{}// 将二维数组中的坐标映射到map中for i : range points{mp[pair{points[i][0], points[i][1]}] struct{}{}}// 将结果设置为一个最大值&#xff0c;防止影响求最小值的逻辑res : ma…...

每日一题:请解释什么是闭包(Closure)?并举一个实际的例子来说明。(前端初级)

今天继续在前端初级笔试题中被AI虐&#xff1a; 碱面的答案&#xff0c;问题&#xff1a;初级&#xff0c;回答&#xff1a;初级https://bs.rongapi.cn/1702510598371151872/14我的回答如下&#xff1a; 闭包是指由大括号包裹的一个区域&#xff0c;这个区域代表了一个变量生效…...

广告主必看!NetMarvel五大优势驱动出海App投放增长

App出海走到今天&#xff0c;流量红利早就不存在&#xff0c;摆在广告主面前最棘手的两个问题&#xff0c;一是不起量&#xff0c;二是买量成本太高&#xff0c;得不偿失。 如何在确保出海应用用户规模有所增长的同时&#xff0c;也保证整体ROI处在较高水平&#xff1f;NetMar…...

数据结构与算法之复杂度

时间复杂度 1.抓大头 2.常数用o(1),低阶函数也用o(1)代替&#xff08;直接去掉&#xff09; 3.取最坏情况 对数相关写法的规定...

ATECLOUD电源测试软件平台如何测试电源纹波?

电源纹波是影响电源稳定性的重要因素&#xff0c;过大的纹波会导致电源模块的工作效率降低&#xff0c;可能使电源模块直接损坏。使用ATECLOUD碘盐测试软件平台对纹波进行测试&#xff0c;检测其工作情况&#xff0c;以确保其稳定性和性能。 电源纹波的产生 电源的纹波通俗的来…...

数据结构与算法:排序算法(2)

目录 堆排序 使用步骤 代码实现 计数排序 适用范围 过程 代码实现 排序优化 桶排序 工作原理 代码实现 堆排序 二叉堆的特性&#xff1a; 1. 最大堆的堆顶是整个堆中的最大元素 2. 最小堆的堆顶是整个堆中的最小元素 以最大堆为例&#xff0c;如果删除一个最大堆的…...

1_图神经网络GNN基础知识学习

文章目录 安装PyTorch Geometric安装工具包 在KarateClub数据集上使用图卷积网络 (GCN) 进行节点分类两个画图函数Graph Neural Networks数据集&#xff1a;Zacharys karate club network.PyTorch Geometric数据集介绍 edge_index使用networkx可视化展示 Graph Neural Networks…...

瑞芯微:基于RK3568的ocr识别

光学字符识别&#xff08;Optical Character Recognition, OCR&#xff09;是指对文本资料的图像文件进行分析识别处理&#xff0c;获取文字及版面信息的过程。亦即将图像中的文字进行识别&#xff0c;并以文本的形式返回。OCR的应用场景 卡片证件识别类&#xff1a;大陆、港澳…...

C++真的是 C加加

&#x1f4dd;个人主页&#xff1a;夏目浅石. &#x1f4cc;博客专栏&#xff1a;C的故事 &#x1f3e0;学习社区&#xff1a;夏目友人帐. 文章目录 前言Ⅰ. 函数重载0x00 重载规则0x01 函数重载的原理名字修饰 Ⅱ. 引用0x00 引用的概念0x01 引用和指针区分0x03 引用的本质0x04…...

java学习--day5 (java中的方法、break/continue关键字)

文章目录 day4作业今天的内容1.方法【重点】1.1为什么要有方法1.2其实已经见过方法1.3定义方法的语法格式1.3.1无参无返回值的方法1.3.2有参无返回值的方法1.3.3无参有返回值的方法1.3.4有参有返回值的方法 2.break和continue关键字2.1break;2.2continue; 3.案例关于方法的练习…...

MFC主框架和视类PreCreateWindow()函数学习

在VC生成的单文档应用程序中&#xff0c;主框架类和视类均具有PreCreateWindow函数&#xff1b; 从名字可知&#xff0c;可在此函数中添加一些代码&#xff0c;来控制窗口显示后的效果&#xff1b; 并且它有注释说明&#xff0c; Modify the Window class or styles here by…...

for forin forof forEach map区别

一、总结 相同点&#xff1a;都是串行遍历。不同点&#xff1a; 二、for of循环 设计目的&#xff1a;遍历所有数据结构的统一方法。原理&#xff1a;会调用数据结构的Symbol.iterator方法。 只要数据结构定义了Symbol.iterator属性&#xff0c;就能用for of遍历它的成员。…...

特殊时间(蓝桥杯)

特殊时间 问题描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 2022年2月22日22:20 是一个很有意义的时间, 年份为 2022 , 由 3 个 2 和 1 个 0 组成, 如果将月和日写成 4 位, 为 0222 , 也是由 3 个 2 和 1 个 0 组 成…...

VUE路由与nodeJS环境搭建

VUE路由 Vue路由是Vue.js提供的路由管理工具&#xff0c;它允许我们在应用程序中实现页面之间的导航&#xff0c;从而使单页面应用程序的开发更加方便。通过Vue路由&#xff0c;我们可以轻松地创建和管理多个视图&#xff0c;并在这些视图之间导航。 Vue路由使用HTML5的Histo…...

抗锯齿的线

抗锯齿的线 右下角的时候h是0,到顶部 h是1&#xff0c;然后中间y相距4个像素&#xff0c;那dy就是0.25 如果让h abs(fract(h - 0.5) - 0.5) 中间一行0.5&#xff0c;第一行 第三行都是0.25&#xff0c;两端都是0 根据插值来看 这里是 如果用h/dy 那么第一行以上&#xff0…...

如何使用高压放大器驱动高容性负载

使用高压放大器驱动高容性负载是一个具有挑战性的任务&#xff0c;需要仔细考虑电路设计和操作技巧。下面西安安泰Aigtek将为您介绍一些关于如何使用高压放大器驱动高容性负载的方法和注意事项。 首先&#xff0c;让我们了解一下高容性负载。高容性负载通常指电容值较大的负载元…...

kubernetes集群证书过期启动失败问题解决方法

1、问题现象 执行kubectl命令异常报告 [rootk8s-master1 ~]# kubectl get node The connection to the server 192.168.227.131:6443 was refused - did you specify the right host or port? [rootk8s-master1 ~]# 查看etcd的日志&#xff0c;报错信息如下 {"level&…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...