前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >多进程服务器

多进程服务器

原创
作者头像
买唯送忧
修改2021-09-14 15:20:55
4.7K0
修改2021-09-14 15:20:55
举报
文章被收录于专栏:虚拟技术学习

一、思路

先与客户端建立好连接, 每次监听到一个客户端之后,都需要产生一个子进程去处理这个连接,然后父进程继续去等待监听,唯一一个要注意的点就是要使用信号来监听子进程是否结束,从而对其进行回收,防止僵尸进程的产生。。。

二、步骤

1、建立连接

(1)socket函数

这里使用的是Ipv4,TCP套接字,所以使用的接口是:lfd = socket(AF_INET, SOCK_STREAM, 0)如果是IPV6把AF_INET后面加个6,如果是UDP,那就是把第二个改成SOCK_DGRAM;

(2)setsockopt函数

主要是端口复用:固定写法就好,第一个参数是socket函数返回值套接字的文件描述符:int opt = 1; setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

(3)bind函数

bind(lfd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));b这个函数主要目的就是将服务器的地址结构绑定到套接字lfd上,所以开始要设置服务器的ser_addr:ser_addr.sin_family = AF_INET, ser_addr.sin_port = htons(8888);ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);端口8888是可由自己设置的,,

(3)listen函数

设置监听的上限的函数,,并不是阻塞监听的函数listen(lfd, 128);

(4)accept函数

accept视为阻塞监听函数,cfd = accept(lfd, (struct sockaddr*)&cli_addr, &cli_addr_len);这个函数主要是完成两个事情:(1)为了得到客户端的地址结构:也就是cli_addr,这个不需要初始化,因为accept函数会设置好,要注意的是cli_addr_len要初始化为sizeof(cli_addr),不然会报错;(2)会返回与客户端进行的通信的套接字cfd;

2、创建子进程

监听到了客户端后,就要开始创建子进程来对这个监听进行处理;pid = fork()

3、子进程处理通信

因为子进程不需要监听连接,使用可以close(lfd);之后便可以进行通信处理

代码语言:javascript
复制
void do_work(int cfd, ProcessTcp tcp){
    char buf[BUFSIZ];
    int ans = 5, n;
    while (ans--){
        n = tcp.Read(cfd, buf, sizeof(buf));
        tcp.Write(cfd, buf, n);
        tcp.Write(STDOUT_FILENO, buf, n);
    }

}

4、父进程回收子进程

父进程使用信号机制来对子进程回收

主要是通过sigaction函数

代码语言:c++
复制
struct sigaction act;
act.sa_handler = catch_child;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
int sigaction(SIGCHLD, &act, NULL);

void catch_child(int sig){
    while ((waitpid(-1, NULL, WNOHANG)) > 0);
}


附录-头文件及CPP文件

ProcessTcp.h

代码语言:javascript
复制
#ifndef __PROCESSTCP_H_
#define __PROCESSTCP_H_

#include<iostream>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<strings.h>
#include<sys/socket.h>
#include<arpa/inet.h>
using namespace std;

class ProcessTcp{
public:
    ProcessTcp(string note){
        cout << note << endl;
    }
    int Socket(int domain, int type, int protocol){
        int lfd = socket(domain, type, protocol);
        if (lfd == -1){
            cout << "socket() fail :" << strerror(errno) << endl;
            exit(1);
        }
        return lfd;
    }
    void setSerAddr(struct sockaddr_in& ser_addr, int flg){
        bzero(&ser_addr, sizeof(ser_addr));
        ser_addr.sin_family = AF_INET;
        ser_addr.sin_port = htons(8888);
        if (flg == 1)
            ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        else
            inet_pton(AF_INET, "127.0.0.1", &ser_addr.sin_addr.s_addr);
    }

    void setSockOpt(int lfd){
        int opt = 1;
        int ret = setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
        if (ret == -1){
            cout << "setsockopt() fail:" << strerror(errno) << endl;
        }
    }

    void Bind(int lfd, const struct sockaddr* ser_addr, socklen_t ser_len){
        int ret = bind(lfd, ser_addr, ser_len);
        if (ret == -1){
            cout << "bind() fail :" << strerror(errno) << endl;
            exit(1);
        }
    }

    void Listen(int lfd, int backlog){
        int ret = listen(lfd, backlog);
        if (ret == -1){
            cout << "listen() fail :" << strerror(errno) << endl;
            exit(1);
        }
    }

    int Accept(int lfd, struct sockaddr* cli_addr, socklen_t* cli_len){
        int cfd;
        do{
            cfd = accept(lfd, cli_addr, cli_len);
            if (cfd == -1){
                if (errno == EINTR)
                    continue;
                else {
                    cout << "accept() --- error: " << strerror(errno) << endl;
                    exit(1);
                }
            }
        }while(0);
        
        return cfd;
    }

    int Connect(int cfd, const struct sockaddr *addr, socklen_t addrlen){
        int ret = connect(cfd, addr, addrlen);
        if (ret == -1){
            cout << "connect() fail: " << strerror(errno) << endl;
            exit(1);
        }
        return ret;
    }

    int Read(int fd, void *buf, size_t count){
        int ret = read(fd, buf, count);
        if (ret == 0){
            close(fd);
            cout << "the client close connection!!!" << endl;
            exit(1);
        } else if (ret == EAGAIN){
            cout << "the error is EAGAIN" << endl;
            exit(1);
        } else if (ret > 0){
            return ret;
        }
        return ret;
    }

    int Write(int fd, const void *buf, size_t count){
        int ret = write(fd, buf, count);
        return ret;
    }


};




#endif

Process_tcp.cpp

代码语言:c++
复制
#include "processTcp.h"
#include<signal.h>
#include<sys/wait.h>

void catch_child(int sig){
    while ((waitpid(-1, NULL, WNOHANG)) > 0);
}

void do_work(int cfd, ProcessTcp tcp){
    char buf[BUFSIZ];
    int ans = 5, n;
    while (ans--){
        n = tcp.Read(cfd, buf, sizeof(buf));
        tcp.Write(cfd, buf, n);
        tcp.Write(STDOUT_FILENO, buf, n);
    }

}

int main(){
  
    int n, ret, ans, cfd;
    pid_t pid;
    struct sockaddr_in serv_addr, cli_addr;
    socklen_t cli_addr_len;
    ProcessTcp tcp("server is ok!!!!");

    int lfd = tcp.Socket(AF_INET, SOCK_STREAM, 0);

    tcp.setSockOpt(lfd);

    tcp.setSerAddr(serv_addr, 1);

    tcp.Bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

    tcp.Listen(lfd, 128);

    cout << "Now arrange receive other connection!!!" << endl;

    while(1){
        cli_addr_len = sizeof(cli_addr);   
        cfd = tcp.Accept(lfd, (struct sockaddr*)&cli_addr, &cli_addr_len);
        pid = fork();
        if (pid < 0){
            cout << "fork() --- error: " << strerror(errno) << endl;
            exit(1);
        } else if (pid > 0){
            close(cfd);
            struct sigaction act;
            act.sa_handler = catch_child;
            sigemptyset(&act.sa_mask);
            act.sa_flags = 0;
            ret = sigaction(SIGCHLD, &act, NULL);
            if (ret == -1){
                cout << "sigaction() --- error:" << strerror(errno) << endl;
                exit(1);
            }
            continue;
        } else if (pid == 0){
            close(lfd);
            break;
        }
    }
    do_work(cfd, tcp);

    
    return 0;
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、思路
  • 二、步骤
    • 1、建立连接
      • (1)socket函数
    • (2)setsockopt函数
      • (3)bind函数
      • (3)listen函数
      • (4)accept函数
    • 2、创建子进程
      • 3、子进程处理通信
        • 4、父进程回收子进程
        • 附录-头文件及CPP文件
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档