unix/linux 系统实现多个进程监听同一个端口

爱被打了一巴掌 2022-09-30 09:45 307阅读 0赞

转自:http://blog.csdn.net/youjun9007228198/article/details/19946129

一直疑惑一个应用app如何才能以多进程,多线程的方式运行。对于多线程可能很好理解,我们只要在进程中启用多线程的模式即可。也就是来一个请求,我们就用函数pthread_create()启用一个线程即可。这样我们的应用就可以在单进程,多线程的模式下工作。

  1. 但我们知道一个应用app通常工作在多进程,多线程的模式下,它的效率是最高的。那么我们如何才能做到多进程模式呢?经验告诉我们,如果多次启动一个进程会报错:“Address already in use!"。这是由于bind函数导致的,由于该端口号已经被监听了。
  2. 其实我们只要在绑定端口号(bind函数)之后,监听端口号之前(listen函数),用fork()函数生成子进程,这样子进程就可以克隆父进程,达到监听同一个端口的目的。好了,废话不多说,我们看一下具体代码。







  1. 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








  1. #include<stdio.h>








    #include<stdlib.h>








    #include<sys/types.h>








    #include<sys/socket.h>








    #include<netinet/in.h>








    #include<unistd.h>















    #define oops(m) {perror(m); exit(1);}








    int


    main


    (){








    int


    sock_id


    ;








    struct


    sockaddr_in


    saddr


    ;








    sock_id


    =


    socket


    (


    PF_INET


    ,


    SOCK_STREAM


    ,


    0


    );








    saddr


    .


    sin_addr


    .


    s_addr


    =


    inet_addr


    (


    127.0.0.1


    );








    saddr


    .


    sin_port


    =


    htons


    (


    9988


    );








    saddr


    .


    sin_family


    =


    AF_INET


    ;








    int


    ret


    =


    bind


    (


    sock_id


    ,


    (


    struct


    sockaddr


    *


    )


    &


    saddr


    ,


    sizeof


    (


    saddr


    ));


    //绑定IP地址和端口








    if


    (


    ret


    ==


    -


    1


    )


    oops


    (


    bind error


    );


    //如果返回-1,则绑定失败,一般为“Address alreay in use”








    int


    i


    ;








    for


    (


    i


    =


    0


    ;


    i


    <


    6


    ;


    i


    ++


    ){


    //连续创建六个子进程








    int


    pid


    =


    fork


    ();








    if


    (


    pid


    ==


    0


    )


    break


    ;








    }








    listen


    (


    sock_id


    ,


    1


    );








    while


    (


    1


    ){








    int


    sock


    =


    accept


    (


    sock_id


    ,


    NULL


    ,


    0


    );








    char


    buf


    [


    128


    ];








    int


    readnum


    ;








    readnum


    =


    read


    (


    sock


    ,


    buf


    ,


    127


    );








    buf


    [


    readnum


    ]


    =


    \0


    ;








    printf


    (


    pid=%d, mesg: %s


    \n





    ,


    getpid


    (),


    buf


    );








    fflush


    (


    stdout


    );








    close


    (


    sock


    );








    }








    return


    1


    ;








    }



来自CODE的代码片 serv.c

接下来我们来启动一下,查看结果如下:

F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 500 3019 2370 0 80 0 - 1315 - tty2 00:00:01 bash
0 S 500 7332 3019 0 80 0 - 466 - tty2 00:00:00 multi_proc
1 S 500 7333 7332 0 80 0 - 466 - tty2 00:00:00 multi_proc
1 S 500 7334 7332 0 80 0 - 466 - tty2 00:00:00 multi_proc
1 S 500 7335 7332 0 80 0 - 466 - tty2 00:00:00 multi_proc
1 S 500 7336 7332 0 80 0 - 466 - tty2 00:00:00 multi_proc
1 S 500 7337 7332 0 80 0 - 466 - tty2 00:00:00 multi_proc
1 S 500 7338 7332 0 80 0 - 466 - tty2 00:00:00 multi_proc

我们可以看到,确实有多个服务(multi_proc)成功起来了,那么这些进程是否能够监听9988这个端口,并且产生竞争呢?我们来写一段客户端的代码做个测试。客户端主要是循环多次请求服务器,并发送字符串。








  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20








  1. #include<stdio.h>








    #include<stdlib.h>








    #include<sys/types.h>








    #include<sys/socket.h>








    #include<unistd.h>








    #include<netinet/in.h>















    int


    main


    (){








    int


    i


    =


    0


    ;








    struct


    sockaddr_in


    saddr


    ;








    saddr


    .


    sin_addr


    .


    s_addr


    =


    inet_addr


    (


    127.0.0.1


    );








    saddr


    .


    sin_port


    =


    htons


    (


    9988


    );








    saddr


    .


    sin_family


    =


    AF_INET


    ;








    int


    addlen


    =


    sizeof


    (


    saddr


    );








    for


    (;


    i


    <


    30


    ;


    i


    ++


    ){








    int


    sock


    =


    socket


    (


    AF_INET


    ,


    SOCK_STREAM


    ,


    0


    );








    connect


    (


    sock


    ,


    (


    struct


    sockaddr


    *


    )


    &


    saddr


    ,


    addlen


    );








    write


    (


    sock


    ,


    Hello Server!”


    ,


    13


    );








    }








    }



来自CODE的代码片 clnt.c

请求执行后,我们看一下,服务器打印的结果!

pid=7738, mesg: Hello Server!

pid=7736, mesg: Hello Server!

pid=7735, mesg: Hello Server!

pid=7734, mesg: Hello Server!

pid=7733, mesg: Hello Server!

pid=7733, mesg: Hello Server!

pid=7737, mesg: Hello Server!

pid=7737, mesg: Hello Server!

pid=7736, mesg: Hello Server!

pid=7735, mesg: Hello Server!

pid=7734, mesg: Hello Server!

pid=7732, mesg: Hello Server!

pid=7733, mesg: Hello Server!

pid=7738, mesg: Hello Server!

pid=7737, mesg: Hello Server!

pid=7736, mesg: Hello Server!

pid=7735, mesg: Hello Server!

pid=7734, mesg: Hello Server!

pid=7732, mesg: Hello Server!

pid=7733, mesg: Hello Server!

pid=7738, mesg: Hello Server!

pid=7737, mesg: Hello Server!

pid=7736, mesg: Hello Server!

pid=7735, mesg: Hello Server!

pid=7734, mesg: Hello Server!

pid=7732, mesg: Hello Server!

pid=7733, mesg: Hello Server!

pid=7738, mesg: Hello Server!

pid=7737, mesg: Hello Server!

pid=7738, mesg: Hello Server!

我们可以看出,这些进程都能监听同一个接口,而且还相互竞争,提高程序效率!

发表评论

表情:
评论列表 (有 0 条评论,307人围观)

还没有评论,来说两句吧...

相关阅读