linux进程间通信---本地socket套接字(二)---多进程实现一个server对应多个client

2023-11-14

**
先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题。想要获取完整源码的,关注公众号后回复“socket2”即可
在这里插入图片描述

一 why

**
一般地,我们会遇到这样一个场景,一个server需要同时并发地处理多个client的连接以及数据交互。
**

二 what

**
一个server对应多个client的连接场景如下:
在这里插入图片描述
实现原理
对于父进程server.c来说

  1. 父进程server.c用来监听每一个client,只实现accept的动作
  2. 每次server.c父进程检测到一个新的client时,就会创建一个新的server子进程,用来和对应的client实现通信(数据交互)
  3. 当对应的client退出时,对应的server子进程也需要退出(读不到数据),否则会产生僵尸进程
    close(cfd); exit();
  4. 父进程server.c检测到子进程退出后,需要回收子进程
    信号 — SIGCHLD()
    waitpid();
  5. 父进程并不需要cfd,所以在父进程中需要关闭cfd, close(cfd);
    对于server子进程来说
    对每个server子进程:
  6. 子进程只需要cfd,并不需要lfd,所以每次进入子进程之后,需要关闭lfd, close(lfd);

**

三 how

**
server.c程序示例,想要获取完整源码的,关注公众号后回复“socket2”即可


void wait_child(int signo)
{
    while (waitpid(0, NULL, WNOHANG) > 0);
    return;
}

int main(int argc, char *argv[])
{
    ......
    //创建socket
    lfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if (lfd == -1) {
        perror("socket error");
        return -1;
    }

    //如果套接字文件存在,删除套接字文件
    unlink("server.sock");

    //初始化server信息
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.sock");

    //绑定
    ret = bind(lfd, (struct sockaddr *)&serv, sizeof(serv));
    if (ret == -1) {
        perror("bind error");
        return -1;
    }

    //设置监听,设置能够同时和服务端连接的客户端数量
    ret = listen(lfd, 36);
    if (ret == -1) {
        perror("listen error");
        return -1;
    }

    while (1) {
        //等待客户端连接
        cfd = accept(lfd, (struct sockaddr *)&client, &len);
        if (cfd == -1) {
            perror("accept error");
            return -1;
        }
        printf("=====client bind file:%s\n", client.sun_path);

        pid = fork();  //每次连接到一个新的客户端就创建一个子进程
        /* 创建子进程同于通信,但是由于这个while循环父子进程都会进来,所以针对子进程,我们需要做退出处理
         */
        ......
    }

    if (pid == 0) {
        while (1) {
            recvlen = recv(cfd, buf, sizeof(buf), 0);
            ......
        }
    }

    ......
}

客户端client代码示例


int main(int argc, char *argv[])
{
    ......

    //创建socket
    lfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if (lfd == -1) {
        perror("socket error");
        return -1;
    }

    //如果套接字文件存在,删除套接字文件
    unlink("client.sock");

    //给客户端绑定一个套接字文件
    client.sun_family = AF_LOCAL;
    strcpy(client.sun_path, "client.sock");
    ret = bind(lfd, (struct sockaddr *)&client, sizeof(client));
    if (ret == -1) {
        perror("bind error");
        return -1;
    }

    //初始化server信息
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.sock");
    //连接
    connect(lfd, (struct sockaddr *)&serv, sizeof(serv));

    while (1) {
        fgets(buf, sizeof(buf), stdin);
        send(lfd, buf, strlen(buf)+1, 0);

        recv(lfd, buf, sizeof(buf), 0);
        printf("recv buf %s\n", buf);
    }

    ......
}

上面的server使用的是创建多进程的方式来实现的,当然我们也可以采用多线程方式来实现,每次连接到一个客户端时,创建一个线程,用来实现和client的数据交互
server.c程序代码


struct s_info {   //定义一个结构体,将地址结构和cfd捆绑
    struct sockaddr_un cliaddr;
    int connfd;
};

void *do_work(void *arg)
{
    int n, i;
    struct s_info *ts = (struct s_info *)arg;
    char buf[1024] = {0};
    int recvlen;

    while (1) {
        recvlen = recv(ts->connfd, buf, sizeof(buf), 0);
        if (recvlen < 0) {
            perror("recv error");
            exit(1);
        } else if (recvlen == 0) {
            printf("client %d close...\n", ts->connfd);
            close(ts->connfd);
            return 0;
        } else {
            printf("recv buf %s\n", buf);
            send(ts->connfd, buf, recvlen, 0);
        }
    }

    close(ts->connfd);

    return NULL;
}

int main(int argc, char *argv[])
{
    int lfd ,ret, cfd;
    struct sockaddr_un serv, client;
    socklen_t len = sizeof(client);
    int i;
    pthread_t tid;
    struct s_info ts[256];    //根据最大线程数创建结构体数组

    //创建socket
    lfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if (lfd == -1) {
        perror("socket error");
        return -1;
    }

    //如果套接字文件存在,删除套接字文件
    unlink("server.sock");

    //初始化server信息
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.sock");

    //绑定
    ret = bind(lfd, (struct sockaddr *)&serv, sizeof(serv));
    if (ret == -1) {
        perror("bind error");
        return -1;
    }

    //设置监听,设置能够同时和服务端连接的客户端数量
    ret = listen(lfd, 36);
    if (ret == -1) {
        perror("listen error");
        return -1;
    }

    while (1) {
        //等待客户端连接
        cfd = accept(lfd, (struct sockaddr *)&client, &len);
        if (cfd == -1) {
            perror("accept error");
            return -1;
        }
        printf("=====client bind file:%s\n", client.sun_path);
        /* 创建子线程用于通信
         */
    }

    close(lfd);
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux进程间通信---本地socket套接字(二)---多进程实现一个server对应多个client 的相关文章

随机推荐

  • 2021-10-30 关于ORACLE 19c DBA_JOBS不能自动执行 LAST_DATE为空 排查方式

    ORACLE DBA JOBS 相关报错解决方式 背景 在新创建的ORACLE 19c单实例数据库环境 恢复生产环境数据后 发现任务调度重启 重建仍不能自动进行调度 后发现DBA JOBS不会自动执行 NEXT DATE正常 LAST DA
  • 从输入URL到页面展示发生了什么?

    目录 1 查询缓存 2 DNS解析 3 建立TCP连接 3次握手 4 客户端发起http请求 5 服务器处理请求 6 服务器响应请求 7 浏览器解析html 8 断开TCP连接 4次挥手 1 查询缓存 从输入url按下回车后 我们进入了第一
  • allegro如何快设置快捷键旋转器件

    在Allegro PCB Editor环境中 设置 在命令栏输入下面命令并回车 funckey iangle 90 按空格以90度旋转选中的物体 funckey R iangle 45 按ctrl R以45度旋转选中的物体 此方法 关闭软件
  • TD添加IE8支持

    今天同事突然安装了IE8了 说TestDirector8 0在IE8 0下无法使用 于是在网上搜索 最后终于知道解决方法了 方法一 下载插件 安装TD自带的浏览器 通用 使用 进入TestDirector 单击Add ins Page 在新
  • 彻底解决Idea控制台的中文乱码问题

    一 出现问题 tomcat输入到idea控制台的信息出现中文乱码 二 解决方案 1 打开idea安装的目录 bin文件夹下 找到idea exe vmoptions和idea64 exe vmoptions两个文件 打开 2 将 Dfile
  • 深度学习中的验证集和超参数简介

    大多数机器学习算法都有超参数 可以设置来控制算法行为 超参数的值不是通过学习算法本身学习出来的 尽管我们可以设计一个嵌套的学习过程 一个学习算法为另一个学习算法学出最优超参数 在多项式回归示例中 有一个超参数 多项式的次数 作为容量超参数
  • Error response from daemon: manifest for java:8 not found: manifest unknown: manifest unknown

    拉取镜像出现这等问题 未找到java 8的守护程序清单的错误响应 清单未知 清单未知 找不到该版本号 换java9试试
  • 【Python】matplotlib设置图片边缘距离和plt.lengend图例放在图像的外侧

    一 问题提出 我有这样一串代码 import matplotlib pyplot as plt plt figure figsize 10 6 此处省略代码 legend append J plt legend legend plt xla
  • 论文阅读 [TPAMI-2022] BDCN: Bi-Directional Cascade Network for Perceptual Edge Detection

    论文阅读 TPAMI 2022 BDCN Bi Directional Cascade Network for Perceptual Edge Detection 论文搜索 studyai com 搜索论文 BDCN Bi Directio
  • 【数据分析】利用机器学习算法进行预测分析(二):线性回归(Linear Regression)

    时间序列预测中的机器学习方法 二 线性回归 Linear Regression 本文是 时间序列预测中的机器学习方法 系列文章的第二篇 如果您有兴趣 可以先阅读前面的文章 数据分析 利用机器学习算法进行预测分析 一 移动平均 Moving
  • Redis集群搭建

    1 安装redis 略 参考 https blog csdn net qq 28326501 article details 114339440 spm 1001 2014 3001 5501 2 复制多份 redis要没有数据 及修改re
  • 文件拷贝

    package Java project 1 import java io public class RecursionDemo public static void main String args try 创建一个字节输入流管道与原文件
  • 数据结构与算法学习笔记

    数据结构与算法 一 数据结构 一组数据的存储结构 二 算法 操作一组数据的方法 三 二者关系 数据结构为算法服务 算法作用在特定的数据结构之上 四 常用数据结构 数组 链表 堆 栈 队列 二叉树 散列表 跳表 图 Trie树 五 常用算法
  • 计算机网络-学习笔记

    计算机网络 学习笔记 1 1 1 概念 组成 功能和分类 概念 计算机网络 是一个将分散的 具有独立功能的计算机系统 通过通信设备与线路连接起来 由功能完善的软件实现资源共享和信息传递的系统 计算机网络是互连的 自治的计算机集合 功能 数据
  • zookeeper的服务容量和自我保护实现思考

    zookeeper的服务容量和自我保护实现思考 1 服务自我保护能力 通过基于租户 Throtting机制 能够对访问请求限流 确保核心服务自我恢复能力 引入租户管理 为后续限流 性能统计等功能提供一个基础的信息 通过Throtting来达
  • 番茄插件遇到的各种安装问题处理

    前言 小编被番茄插件折磨疯了 但最终的还是终究是找到了屠灭巨龙的方法 遇到安装成功 但是打开vs不显示图标 番茄插件没法正常使用的情况 这种大多是多次安装造成的问题 修复重新打开 我们发现之前装的插件没了 这时候需要去做删除注册事件表 再重
  • C语言中的数组为什么不可赋值给另一个数组?数组的初始化,除了遍历赋值,还可以怎么被赋值?

    C语言中的数组为什么不可赋值给另一个数组 因为数组为指针常量 如 int a int b b a 是错误地 因为 int a 是 int const a int b 是 int const b 一个指针常量不可以被另一个指针常量修改 地址常
  • CMOS图像传感器——相位对焦

    之前介绍了许多自动对焦的方案 自动对焦方法学习 沧海一升的博客 CSDN博客自动对焦的各类方法学习介绍https blog csdn net qq 21842097 article details 121373263 在里面提到了遮蔽像素相
  • 【学习笔记】C++STL和泛型编程-侯捷

    文章目录 C 标准库 体系结构与内核分析 第一讲 1 header 版本和重要资源 2 STL体系结构介绍 2 1 STL六大部件 Components 2 2 STL容器的前闭后开区间 2 3 基于范围的for循环 ranged base
  • linux进程间通信---本地socket套接字(二)---多进程实现一个server对应多个client

    先给自己打个广告 本人的微信公众号正式上线了 搜索 张笑生的地盘 主要关注嵌入式软件开发 股票基金定投 足球等等 希望大家多多关注 有问题可以直接留言给我 一定尽心尽力回答大家的问题 想要获取完整源码的 关注公众号后回复 socket2 即