多进程服务器端

多进程服务端

  1. 利用信号回收子进程例子(利用子进程结束后向父进程发送SIGCHLD信号来回收子进程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    #include <me.h>

    //子进程结束信号
    void read_childproc(int signo)
    {
    int status;
    pid_t id = waitpid(-1,&status,WNOHANG);
    if (WIFEXITED(status))
    {
    printf("Removed proc id: %d \n",id);
    printf("Child send: %d \n",WEXITSTATUS(status));
    }
    }

    int main(int argc,char *argv[])
    {
    pid_t pid;
    struct sigaction act;
    act.sa_handler = read_childproc;
    sigemptyset(&act.sa_mask);//信号处理函数执行时期的信号屏蔽字
    act.sa_flags = 0;
    sigaction(SIGCHLD,&act,0);

    pid = fork();
    if (pid == 0)
    {
    puts("Hi! I'm child process.");
    sleep(10);
    return 12;
    }
    else
    {
    printf("Child proc id: %d \n",pid);
    pid = fork();
    if (pid == 0)//第二个子进程
    {
    puts("Hi! I'm child process");
    sleep(10);
    exit(24);
    }
    else//主进程
    {
    int i;
    printf("Child proc id: %d \n",pid);
    for (i=0; i<5; i++)
    {
    puts("wait...");
    sleep(5);
    }
    }
    }
    return 0;
    }

  2. 通过多个进程来实现并发(

    由父进程来监听连接请求,多个子进程来处理逻辑 ,因为fork后文件描述符也被复制一份到子进程,因为一个端口对应一个套接字,而此时文件描述符多了1份,

    1. 让唯一的父进程处理连接请求,那么去掉fork前连接成功的客户端socket fd,

    2. 多个子进程只需要负责数据,不需要监听,那么关闭监听的socket fd

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    #include <me.h>

    #define BUF_SIZE 30

    void read_childproc(int);

    int main(int argc,char *argv[])
    {
    int serv_sock,clnt_sock;
    struct sockaddr_in serv_adr,clnt_adr;
    pid_t pid;
    struct sigaction act;
    int str_len,state;
    socklen_t adr_sz;
    char buf[BUF_SIZE];
    if (argc != 2)
    {
    printf("Usage : %s <port> \n",argv[0]);
    exit(1);
    }

    //注册信号处理函数
    act.sa_handler = read_childproc;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    state = sigaction(SIGCHLD,&act,0);
    if (state == -1)
    error_handle("sigaction error")

    serv_sock = socket(AF_INET,SOCK_STREAM,0);
    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(atoi(argv[1]));

    if (bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1)
    error_handle("bind() error")

    if (listen(serv_sock,5) == -1)
    error_handle("listen() error")

    while(1)
    {
    adr_sz = sizeof(clnt_adr);
    clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_adr,&adr_sz);
    if (clnt_sock == -1)
    continue;
    else
    puts("new client connected...");
    pid = fork();
    if (pid == -1)//连接成功,但是fork失败
    {
    close(clnt_sock);
    continue;
    }

    if (pid == 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 disconnected...");
    return 0;
    }
    else
    {
    //父进程用不到此套接字(因为已经交给子进程来处理了)
    close(clnt_sock);
    }
    }
    close(serv_sock);//父进程结束,服务器端套接字关闭
    return 0;
    }

    void read_childproc(int signo)
    {
    pid_t pid;
    int status;
    pid = waitpid(-1,&status,WNOHANG);//不阻塞回收子进程
    printf("removed proc id: %d \n",pid);
    }
  3. 分割IO程序,开子进程让2个进程分别In和out

    普通回声服务器客户端(写了之后在读:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    #include <me.h>

    #define BUF_SIZE 1024
    int main(int argc,char *argv[])
    {
    int sock;
    char message[BUF_SIZE];
    int str_len;
    struct sockaddr_in serv_adr;

    if (argc != 3)
    {
    printf("Usage : %s <IP> <port>\n",argv[0]);
    exit(1);
    }

    sock = socket(AF_INET,SOCK_STREAM,0);
    if (sock == -1)
    error_handle("socket() error");

    memset(&serv_adr,0,sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
    serv_adr.sin_port = htons(atoi(argv[2]));

    if (connect(sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1)
    error_handle("connect() error")
    else
    puts("connected...");

    //已经连接上了服务器
    while(1)
    {
    fputs("Input message(Q to quit): ",stdout);
    fgets(message,BUF_SIZE,stdin);

    if (!strcmp(message,"q\n") || !strcmp(message,"Q\n"))
    break;

    write(sock,message,strlen(message));
    str_len = read(sock,message,BUF_SIZE-1);
    message[str_len] = 0;
    printf("Message from server: %s",message);
    }
    close(sock);
    return 0;
    }

    开子进程同时读和写:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    #include <me.h>
    #define BUF_SIZE 30

    void read_routine(int,char*);
    void write_routine(int,char*);

    int main(int argc,char *argv[])
    {
    int sock;
    pid_t pid;
    char buf[BUF_SIZE];
    struct sockaddr_in serv_adr;
    if (argc != 3)
    {
    printf("Usage : %s <IP> <port> \n",argv[0]);
    exit(1);
    }

    sock = socket(AF_INET,SOCK_STREAM,0);
    memset(&serv_adr,0,sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
    serv_adr.sin_port = htons(atoi(argv[2]));

    if (connect(sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1)
    error_handle("connect() error");
    //IO分割
    pid = fork();
    if (pid == 0)
    {
    write_routine(sock,buf);
    }
    else
    {
    read_routine(sock,buf);
    }
    close(sock);
    return 0;
    }

    void read_routine(int sock,char *buf)
    {
    while(1)
    {
    int str_len = read(sock,buf,BUF_SIZE);
    if (str_len == 0)
    return ;
    buf[str_len] = 0;
    printf("Message from server: %s",buf);
    }
    }

    void write_routine(int sock,char *buf)
    {
    while(1)
    {
    fgets(buf,BUF_SIZE,stdin);
    if (!strcmp(buf,"q\n") || !strcmp(buf,"Q\n"))
    {
    shutdown(sock,SHUT_WR);
    return ;
    }
    write(sock,buf,strlen(buf));
    }
    }

来自<<TCP/IP 网络编程 尹圣雨>>