【TCP/IP】多进程服务器的实现(进阶) - 多进程服务器模型及代码实现

news2025/2/13 0:10:42

        经过前面的铺垫,我们已经具备实现并发服务器的基础了,接下来让我们尝试将之前的单任务回声服务器改装成多任务并发模式吧!

多任务回声服务器模型

        在编写代码前,先让我们大致将多任务(回声)服务器的模型抽象一下,如下图所示:

        当客户端请求服务(连接请求)时,回声服务器端便会创建子进程以提供服务。为了完成这些任务,需要经过以下过程:

  • 第一阶段 : 回声服务器端(父进程)调用accept函数受理客户端发来的连接请求。
  • 第二阶段 : 父进程套接字的文件描述符被拷贝传递给子进程 。
  • 第三阶段 : 子进程利用传递来的文件描述符提供服务。

        OK,让我们开始试着用代码去实现

multi_echoserver.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 1024

void Handler_childproc(int sig)
{
    int status;
    pid_t pid = waitpid(-1, &status, WNOHANG);
    printf("Removed process id: %d \n", pid);
}

void Sender_message(char *message)
{
    puts(message);
    exit(1);
}

int main(int argc, char *argv[])
{
    int serv_sock, clnt_sock;
    int str_len, state, port;
    struct sockaddr_in serv_adr, clnt_adr;
    struct sigaction act;
    pid_t pid;
    socklen_t adr_sz;
    char buf[BUF_SIZE];
    //防止僵尸进程
    act.sa_handler = Handler_childproc;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    state = sigaction(SIGCHLD, &act, 0);

    serv_sock = socket(PF_INET, SOCK_STREAM, 0);
    if (serv_sock == -1)
    {
        Sender_message((char *)"Socket creation error");
    }

    printf("Please input the port of socket that you want to create:\n");
    scanf("%d", &port);
    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(port);

    if (bind(serv_sock, (struct sockaddr *)&serv_adr, sizeof(serv_adr)) == -1)
    {
        Sender_message((char *)"bind error");
    }
    if (listen(serv_sock, 5) == -1)
    {
        Sender_message((char *)"listen error");
    }

    while (1)
    {
        adr_sz = sizeof(clnt_adr);
        //accept后(受理客户端发来的请求)创建子进程
        clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_adr, &adr_sz);
        if (clnt_sock == -1)
        {
            continue;
        }
        else
        {
            puts("New client was connected...");
        }

        pid = fork();

        switch (pid)
        {
        case -1:
        {
            close(clnt_sock);
            continue;
        }
        case 0: //子进程
        {
       //关闭服务器端套接字的文件描述符(很重要,若不处理会使服务器端套接字最终无法正常关闭)
            close(serv_sock);
            while ((str_len = read(clnt_sock, buf, BUF_SIZE)) != 0)
            {
                write(clnt_sock, buf, str_len);
            }
            close(clnt_sock);
            puts("Client was disconnected...");
            return 0;
        }
        default: //父进程
        {
            //关闭客户端连接
            close(clnt_sock);
            break;
        }
        }
    }
    close(serv_sock);
    return 0;
}

        * 可以直接用之前编译的回声客户端代码,参见: 回声客户端缺陷的解决 这一篇文章

        运行结果:

        启动多个回声客户端后,没啥问题,功能正常~

补充:

        在上述代码中(multi_echoserver),调用fork函数后,父进程会复制2个套接字的文件描述符给子进程(一个是服务器,一个是客户端),过程如下图所示:

        当1个套接字中衍生出了2个文件描述符时,只有这2个描述符都被销毁后,套接字才能被完全销毁。(无论是在客户端还是服务器端,依此类推)因此,在调用fork函数后,一定要将无关的套接字的文件描述符处理好,否则将导致套接字无法正常关闭。 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mac下部署和访问 Kubernetes 仪表板(Dashboard)

简介 Dashboard 是基于网页的 Kubernetes 用户界面。 你可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中&#xff0c;也可以对容器应用排错&#xff0c;还能管理集群资源。 你可以使用 Dashboard 获取运行在集群中的应用的概览信息&#xff0c;也可以创建或者修改 Kub…

技术分享——隐私计算简介

随着数据规模的不断扩大和网络技术的快速发展&#xff0c;数据安全和隐私保护成为了热门的话题。隐私计算作为一种新兴的数据安全和隐私保护技术&#xff0c;为数据安全和隐私泄露问题提供了新的思路和方法。 2020年10月19日&#xff0c;Gartner发布2021年前沿战略科技趋势&am…

VTK源码编译安装记录与教程(VS2019+QT5.15.2+PCL1.12.1+VTK9.1.0配置,超详细)

因为PCL库&#xff08;傻瓜式安装&#xff09;中自动安装的VTK库并不完整&#xff0c;不支持QT环境的UI界面开发&#xff0c;于是&#xff0c;想用QT在VS2019上开发图形界面程序&#xff0c;需要单独自己通过VTK源码编译安装&#xff0c;再进行配置。本人安装时开发环境已经装好…

2023拒绝行业内卷!八年软件测试月薪30K*16薪行业心得 想入行必看

目前工作做软件测试工作8年&#xff0c;属于高级测试员那个级别吧&#xff01;现在看到各行各业的人都在转行学习软件测试&#xff0c;想给大家一些学习建议和忠告。 很多粉丝都跟我说今年行情很差&#xff0c;找不到工资&#xff0c;真的找不到工作了吗&#xff1f; 我们常在网…

simhash原理以及用python3实现simhash算法详解(附python3源码)

1. 为什么需要Simhash? 传统相似度算法:文本相似度的计算,一般使用向量空间模型(VSM),先对文本分词,提取特征,根据特征建立文本向量,把文本之间相似度的计算转化为特征向量距离的计算,如欧式距离、余弦夹角等。 缺点:大数据情况下复杂度会很高。 Simhash应用场景:…

Graph Learning笔记 - 长尾分布问题

Graph Learning笔记 - 长尾分布问题 分享四篇论文入门图神经网络时的学习笔记。 SL-DSGCN 论文&#xff1a;Investigating and Mitigating Degree-Related Biases in Graph Convolutional Networks 来源&#xff1a;2020CIKM 概要 GCN在图的半监督学习上能取得良好表现&a…

lora,固定模特+固定衣服,怎么实现?

在电商行业&#xff0c;经常会有一个需求&#xff0c;就是把固定的衣服让模型穿上&#xff0c;然后拍很多的图片&#xff0c;放在商品主图、详情页、买家秀...... 人工智能发展到现在&#xff0c;最近aigc也挺热门的&#xff0c;有没有办法用“人工智能”算法就实现这个功能&a…

逆向汇编反汇编——函数分析

add esp,8就是把esp调整到函数调用之前的状态&#xff0c;用以平衡堆栈 默认采用的是cdcall&#xff1a;外平栈 stdcall:内平栈 什么是堆栈平衡&#xff1f; 》原来的堆栈是什么样的&#xff0c;函数调用之后堆栈还是什么样的(即&#xff0c;esp和ebp的值保持不变)&#xf…

掌握Scala数据结构(2)MAP、TUPLE、SET

一、映射 (Map) &#xff08;一&#xff09;不可变映射 1、创建不可变映射 创建不可变映射mp&#xff0c;用键->值的形式 创建不可变映射mp&#xff0c;用(键, 值)的形式 注意&#xff1a;Map是特质&#xff08;Scala里的trait&#xff0c;相当于Java里的interface&#…

git选择指定分支中的指定目录进行合并

指定路径合并 先进入branch A &#xff1a; git checkout branchA 将dir2中的变更转移至branchA&#xff1a; git checkout branchB dir2 所有变更将出现在branchA中的dir2中&#xff0c;检查后提交即可。 git commit -m "sync branchB dir2 to branchA" 也可以…

读财报丨第二增长曲线渐显,但涂鸦智能的未来还看PaaS业务?

2022年以来&#xff0c;全球物联网行业持续低迷&#xff0c;赛道内不少玩家出现业绩下滑&#xff0c;而且陆续传出巨头企业关停相关业务板块的消息。这背后是消费电子行业库存积压&#xff0c;客户需求难以释放等宏观因素&#xff0c;导致IoT领域面临一定的经营困境。 近日&am…

STM32——07-STM32定时器Timer

定时器介绍 软件定时 缺点&#xff1a;不精确、占用 CPU 资源 void Delay500ms () //11.0592MHz { unsigned char i , j , k ; _nop_ (); i 4 ; j 129 ; k 119 ; do { do { while ( -- k ); } while ( -- j ); } while ( -- i ); } 定时器工…

108-Spring的底层原理(下篇)

这里续写上一章博客&#xff08;107章博客&#xff09;&#xff1a; Spring 声明式事务的支持&#xff1a; 编程式事务&#xff1a;在业务代码中添加事务控制代码&#xff0c;这样的事务控制机制就叫做编程式事务 声明式事务&#xff1a;通过xml或者注解配置的方式达到事务…

【Linux】进程间通信(管道)

文章目录 进程通信的目的进程间通信发展进程间通信分类管道System V IPCPOSIX IPC 管道什么是管道管道的读写规则管道的特点&#xff1a;匿名管道处理退出问题命名管道创建一个命名管道匿名管道与命名管道的区别命名管道的打开规则 进程通信的目的 数据传输&#xff1a;一个进程…

应用层协议 —— websocket

websocket介绍 websocket是从HTML5开始支持的一种网页端和服务端保持长连接的消息推送机制。 传统的web程序都是属于“一问一答”的形式&#xff0c;即客户端给服务器发送了一个HTTP请求&#xff0c;服务器给客户端返回一个HTTP响应。这种情况下服务器属于被动的一方&#xff…

前端食堂技术周刊第 86 期:Remix 拥抱 RSC、2023 React 生态系统、从 0 实现 RSC、字节跳动 Mobile DevOps 工程实践

美味值&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f; 口味&#xff1a;椰子水 食堂技术周刊仓库地址&#xff1a;https://github.com/Geekhyt/weekly 本期摘要 Remix 拥抱 RSCWebContainers 原生支持 npm、yarn 和 pnpm2023 React 生态系…

MySQL InnoDB集群部署及管理全教程

MySQL InnoDB 集群提供完整的高可用性 MySQL 的解决方案。通过使用MySQL Shell附带的AdminAPI&#xff0c;您可以轻松 配置和管理至少三个MySQL服务器的组 实例以充当 InnoDB 集群。 InnoDB 集群中的每个 MySQL 服务器实例都运行 MySQL 组复制&#xff0c;提供复制机制 InnoDB…

LoadRunner 2023 下载和安装

下载 LoadRunner目前最新的版本是2023版&#xff0c;需要到Micro Focus公司的官网注册账号然后申请下载&#xff0c;比较麻烦&#xff0c;这里我把大家常用的社区版本&#xff0c;搬运到阿里云盘上&#xff0c;供下载&#xff1a; https://www.aliyundrive.com/s/WtHSzD4MrXw …

面试了十几家软件测试公司谈谈我最近面试的总结

由于互联网裁员&#xff0c;最近在 bosss 上投了些简历&#xff0c;测试开发岗&#xff0c;看看目前市场情况。 虽然都在说大环境不好&#xff0c;失业的人很多&#xff0c;我最近约面试的还是比较多的&#xff0c;说说最近的体会吧&#xff0c;希望能给大家提供价值。 1、20K…

教你制作一个简单的进销存管理软件,值得收藏!

首先要制作进销存软件&#xff0c;要具体了解进销存到底是什么含义&#xff0c;这三个字分别代表什么流程&#xff0c;在整个进销存管理中的组成。再根据不同的流程制作进销存软件相对应的部分—— 01进销存的定义 “进”——采购 采购是进销存管理的重要组成部分&#xff0…