IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> TCP/IP,多进程服务器,可多连接,通过fork创建子进程并由子进程维护与客户端的连接,通过信号量回收子进程 -> 正文阅读

[系统运维]TCP/IP,多进程服务器,可多连接,通过fork创建子进程并由子进程维护与客户端的连接,通过信号量回收子进程

TCP/IP,多进程服务器,可多连接,通过fork创建子进程并由子进程维护与客户端的连接,通过信号量回收子进程

一、思路
1、服务端创建并维护用于监听端口的套接字
2、当监听套接字accept到客户端的连接后,使用fork创建子进程
3、通过判断fork的返回值分辨父进程和子进程,
4、父进程关闭与客户端通信的套接字,子进程关闭监听的套接字,原因见:

Linux下fork复制出来的进程数据中文件描述符的共享状态,.data数据拷贝的设定,无用文件描述符需要关闭,仅保留当前进程需要使用的文件描述符
5、客户端关闭后,与之相连的子进程退出变成僵尸进程,父进程通过信号量回收子进程

二、服务端连接思路
1、父进程创建子进程并进行判断

Listen(lfd,128);
    while(1)
    {
        cfd = Accept(lfd,(struct sockaddr*)&clt_addr,&clt_addr_len);
        pid = fork();
        if(pid < 0)
        {
            sys_err("fork error");
        }
        else if(pid == 0)
        {
            close(lfd);
            break;
        }
        else
        {
            close(cfd);
        }
    }
    if(pid == 0)
    {
        while(1)
        {
            ret = read(cfd,buf,sizeof(buf));
            if(ret == 0)
            {
                printf("client is been closed,close\n");
                close(cfd);
                exit(1);
            }
            else if(ret == -1)
            {
                perror("read error");
            }
            else
            {
                for(int i = 0;i<ret;i++)
                {
                    buf[i] = toupper(buf[i]);
                }
            }
            
            write(cfd, buf ,ret);
            write(STDOUT_FILENO,buf,ret);
        }
    }

2、父进程结合信号量回收子进程

void catch_child(int signum)
{
    if(signum == SIGCHLD)
    {
        int status;
        pid_t id = waitpid(-1,status,WNOHANG);
        if(WIFEXITED(status))
        {
            printf("Process ended, id = %d",id);
            printf("child send num %d", WEXITSTATUS(status));
        }
    }
}

int main(int argc,char *argv[])
{
    int lfd,cfd;
    pid_t pid;
    int ret;
    struct sockaddr_in srv_addr,clt_addr;
    char buf[BUFSIZ];
    signal(SIGCHLD,catch_child);

    socklen_t clt_addr_len;

三、服务端整体代码

#include <string.h>
#include <sys/wait.h>
#include "tcp_socket.h"

#define SRV_PORT 9527

void catch_child(int signum)
{
    if(signum == SIGCHLD)
    {
        int status;
        pid_t id = waitpid(-1,status,WNOHANG);
        if(WIFEXITED(status))
        {
            printf("Process ended, id = %d",id);
            printf("child send num %d", WEXITSTATUS(status));
        }
    }
}

int main(int argc,char *argv[])
{
    int lfd,cfd;
    pid_t pid;
    int ret;
    struct sockaddr_in srv_addr,clt_addr;
    char buf[BUFSIZ];
    signal(SIGCHLD,catch_child);

    socklen_t clt_addr_len;
    bzero(&srv_addr,sizeof(srv_addr));

    srv_addr.sin_family = AF_INET;
    srv_addr.sin_port = htons(SRV_PORT);
    srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    lfd = Socket(AF_INET,SOCK_STREAM,0);
    Bind(lfd,(struct sockaddr *)&srv_addr, sizeof(srv_addr));
    
    clt_addr_len = sizeof(clt_addr);

    Listen(lfd,128);
    while(1)
    {
        cfd = Accept(lfd,(struct sockaddr*)&clt_addr,&clt_addr_len);
        pid = fork();
        if(pid < 0)
        {
            sys_err("fork error");
        }
        else if(pid == 0)
        {
            close(lfd);
            break;
        }
        else
        {
            close(cfd);
        }
    }
    if(pid == 0)
    {
        while(1)
        {
            ret = read(cfd,buf,sizeof(buf));
            if(ret == 0)
            {
                printf("client is been closed,close\n");
                close(cfd);
                exit(1);
            }
            else if(ret == -1)
            {
                perror("read error");
            }
            else
            {
                for(int i = 0;i<ret;i++)
                {
                    buf[i] = toupper(buf[i]);
                }
            }
            
            write(cfd, buf ,ret);
            write(STDOUT_FILENO,buf,ret);
        }
    }
    return 0;
}

四、与客户端连接结果,客户端代码见
客户端简单实例
在这里插入图片描述
1、多个客户端均成功与服务器通信
在这里插入图片描述
2、子进程均被回收,未产生僵尸进程

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-04-15 00:46:32  更:2022-04-15 00:51:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 22:19:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码