当前位置: 首页 > 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() 函数创建子进程的服务器适用于简单的并发场景和较小规模的应用,但在大规模高并发、资源消耗较大或需要更高可伸缩性的情况下,可能需要考虑其他并发模型,如多线程或事件驱动模型。

http://www.lryc.cn/news/171840.html

相关文章:

  • 缺失的第一个正数:高效解法与技术
  • 常用的辅助网站(持续更新)
  • LeetCode 75 - 01 : 最小面积矩形
  • 每日一题:请解释什么是闭包(Closure)?并举一个实际的例子来说明。(前端初级)
  • 广告主必看!NetMarvel五大优势驱动出海App投放增长
  • 数据结构与算法之复杂度
  • ATECLOUD电源测试软件平台如何测试电源纹波?
  • 数据结构与算法:排序算法(2)
  • 1_图神经网络GNN基础知识学习
  • 瑞芯微:基于RK3568的ocr识别
  • C++真的是 C加加
  • java学习--day5 (java中的方法、break/continue关键字)
  • MFC主框架和视类PreCreateWindow()函数学习
  • for forin forof forEach map区别
  • 特殊时间(蓝桥杯)
  • VUE路由与nodeJS环境搭建
  • 抗锯齿的线
  • 如何使用高压放大器驱动高容性负载
  • kubernetes集群证书过期启动失败问题解决方法
  • nvm使用的注意事项和常用命令。
  • 代码大全阅读随笔(七)
  • 用户与权限管理
  • mysql集群使用nginx配置负载均衡
  • 蓝桥杯每日一题2023.9.21
  • 知识联合——函数指针数组
  • 【Nginx26】Nginx学习:日志与镜像流量复制
  • Stability AI发布基于稳定扩散的音频生成模型Stable Audio
  • 华为OD机试 - 计算面积 - 逻辑分析(Java 2023 B卷 100分)
  • Ganache本地测试网+cpolar内网穿透实现公网访问内网
  • 【每日一题】ARC071D - ### | 前缀和 | 简单