首页 > 代码库 > C++ 异步 IO(二) 服务器端多进程

C++ 异步 IO(二) 服务器端多进程

通过多线程或多进程可以减弱阻塞IO的负面作用。

/* For sockaddr_in */
#include <netinet/in.h>
/* For socket functions */
#include <sys/socket.h>

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX_LINE 16384

char
rot13_char(char c)
{
    /* We don‘t want to use isalpha here; setting the locale would change
     * which characters are considered alphabetical. */
    if ((c >= a && c <= m) || (c >= A && c <= M))
        return c + 13;
    else if ((c >= n && c <= z) || (c >= N && c <= Z))
        return c - 13;
    else
        return c;
}

void
child(int fd)
{
    char outbuf[MAX_LINE+1];
    size_t outbuf_used = 0;
    ssize_t result;

    while (1) {
        char ch;
        result = recv(fd, &ch, 1, 0);
        if (result == 0) {
            break;
        } else if (result == -1) {
            perror("read");
            break;
        }

        /* We do this test to keep the user from overflowing the buffer. */
        if (outbuf_used < sizeof(outbuf)) {
            outbuf[outbuf_used++] = rot13_char(ch);
        }

        if (ch == \n) {
            send(fd, outbuf, outbuf_used, 0);
            outbuf_used = 0;
            continue;
        }
    }
}

void
run(void)
{
    int listener;
    struct sockaddr_in sin;

    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = 0;
    sin.sin_port = htons(40713);

    listener = socket(AF_INET, SOCK_STREAM, 0);

#ifndef WIN32
    {
        int one = 1;
        setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
    }
#endif

    if (bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
        perror("bind");
        return;
    }

    if (listen(listener, 16)<0) {
        perror("listen");
        return;
    }



    while (1) {
        struct sockaddr_storage ss;
        socklen_t slen = sizeof(ss);
        int fd = accept(listener, (struct sockaddr*)&ss, &slen);
        if (fd < 0) {
            perror("accept");
        } else {
            if (fork() == 0) {
                child(fd);
                exit(0);
            }
        }
    }
}

int
main(int c, char **v)
{
    run();
    return 0;
}

1. 函数 rot13_char(char) 是用来转换字符的,{A,a}~{M,m} -> {N,n}~{Z,z} 其余符号不变

2. server监听端口并响应连接

  2.1 listener = socket(AF_INET, SOCKET_STREAM, 0) 创建套接字

  2.2 bind(listener, (sockaddr*)&sin, size(sin)) 绑定套接字到端口

  2.3 listen(listener, 16) 开始监听

  2.4 struct sockaddr_storage ss;

      socklen_t slen = sizeof(ss);

      int fd = accept(listener, (struct sockaddr*)&ss, &slen);

    每个fd标识响应的一个请求

  2.5 if (fork() == 0) { child(fd); exit(0);}

    创建一个子进程,响应一个请求     

3. server端子进程的处理函数

  3.1 void child(int fd) 处理函数接口

  3.2 result = recv(fd, &ch, 1, 0); 从client端读取一个字符

         send(fd, outbuf, outbuf_used, 0); 发送一个字符串到client端

1. 创建子进程的过程

    pid_t pid;

     switch (pid = fork())
     {
     case -1:

         perror("The fork failed!";
         break;
     case 0:
         printf("I‘m a child!";
         system("touch /home/tom/abc.txt";
         _exit(0);

     default:
         printf("Child‘s pid is %d\n",pid);
     }

程序会输出default的内容,并且创建 abc.txt

原因是:创建子进程时,子进程复制了父进程的内容。子进程和父进程同时进入switch语句,但父子进程的pid并不同,因此进入不同的case。