TCP并发服务器模型(一)

来源:互联网 发布:钟镇涛破产原因 知乎 编辑:程序博客网 时间:2024/06/05 06:34

本篇叙述的TCP并发服务器模型如下图所示:
服务器创建并绑定套接字后fork出几个子进程,子进程中分别进行accept(该函数为阻塞函数)、recv、处理数据然后再次acept,这样循环下去。所有客户端发来的信息都是直接由子进程处理。
这里写图片描述

例程
代码如下,在处理客户端请求之前,服务器先fork了3个子进程,然后将客户端的请求直接交由子进程处理。
该例程中,服务器fork子进程后,子进程监听并接收客户端的信息,然后打印客户端发来的信息和自己的id(id代表自己是第几个子进程)

服务器端代码:

/**************************************author:arvikpurpose:test the server simultaneityemail:1216601195@qq.comcsdn: http://blog.csdn.net/u012819339**************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <signal.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#define BUFFLEN 1024#define SERVER_PORT 8887#define BACKLOG 5#define PIDNUMB 3static void handle_connect(int s_s, int id){    int s_c;    struct sockaddr_in from;  //client addr    socklen_t len = sizeof(from);    while(1)    {        s_c = accept(s_s, (struct sockaddr*)&from, &len);        char buff[BUFFLEN];        memset(buff, 0, BUFFLEN);        int n = recv(s_c, buff, BUFFLEN, 0);  //non block           if(n > 0)        {            printf("This process id is: %d \nreveive from client: %s\n", id, buff);        }        close(s_c);    }}void sig_int(int num){    exit(1);}int main(int argc, char **argv){    int s_s;    struct sockaddr_in local;    signal(SIGINT, sig_int);    s_s = socket(AF_INET, SOCK_STREAM, 0);    memset(&local, 0, sizeof(local));    local.sin_family = AF_INET;    local.sin_addr.s_addr = htonl(INADDR_ANY);    local.sin_port = htons(SERVER_PORT);    bind(s_s, (struct sockaddr*)&local, sizeof(local));    listen(s_s, BACKLOG);    pid_t pid[PIDNUMB];    for(int i = 0; i<PIDNUMB; i++)    {        pid[i] = fork();        if(pid[i] == 0)        {            handle_connect(s_s, i);        }    }    sleep(100);    close(s_s);    return 0;}

客户端代码:

/**************************************author:arvikpurpose:test the server simultaneityemail:1216601195@qq.comcsdn: http://blog.csdn.net/u012819339**************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <unistd.h>#include <signal.h>#define BUFFLEN 24#define SERVER_PORT 8887int main(){    int s_c;    struct sockaddr_in server;    char buff[] = "hello";    s_c = socket(AF_INET, SOCK_STREAM, 0);    memset(&server, 0, sizeof(server));    server.sin_family = AF_INET;    server.sin_addr.s_addr = htonl(INADDR_ANY); //any local address    server.sin_port = htons(SERVER_PORT);    connect(s_c, (struct sockaddr*)&server, sizeof(server));    send(s_c, buff, strlen(buff), 0);    sleep(1);    close(s_c);    return 0;}

到此问个问题,
当一个客户端送来信息后,到底是哪个子进程接收并处理信息呢?服务器端3个子进程会由于争相接收理客户端的连接而都得到连接权(或都得不到连接权)呢?

不知其解,故展开验证:
1. 启动服务器后,我依次启动了客户端(每次都是等服务器处理完上个请求后才启动客户端的),发现三个子进程依次轮流来接收信息。

[root@F12 t1]# ./server[root@F12 t1]# ./clientThis process id is: 0 reveive from client: hello[root@F12 t1]# [root@F12 t1]# ./clientThis process id is: 1 reveive from client: hello[root@F12 t1]# ./clientThis process id is: 2 reveive from client: hello[root@F12 t1]# ./clientThis process id is: 0 reveive from client: hello
  1. 同时启动两个客户端
[root@F12 t1]# ./client & ./client[1] 20805This process id is: 1 reveive from client: helloThis process id is: 2 reveive from client: hello[root@F12 t1]# [1]+  Done                    ./client[root@F12 t1]#
  1. 同时启动四个客户端,这时发现处理消息的服务器子进程没那么规律了
[root@F12 t1]# ./client & ./client & ./client & ./client[1] 20809This process id is: 1 reveive from client: helloThis process id is: 1 reveive from client: hello[2] 20810[3] 20811This process id is: 2 reveive from client: helloThis process id is: 1 reveive from client: hello[1]   Done                    ./client[2]-  Done                    ./client[3]+  Done                    ./client[root@F12 t1]# [root@F12 t1]# [root@F12 t1]# ./client & ./client & ./client & ./client[1] 20832[2] 20833[3] 20834This process id is: 0 reveive from client: helloThis process id is: 2 reveive from client: helloThis process id is: 1 reveive from client: helloThis process id is: 0 reveive from client: hello[1]   Done                    ./client[root@F12 t1]# [2]-  Done                    ./client[3]+  Done                    ./client[root@F12 t1]# 

由试验现象可对上述问题做个简单回答,操作系统在某一时刻会安排服务器子进程中的一个来处理客户端发来的连接,对于每一个客户端的连接,服务器子进程有且只有一个接收并进行处理。

1 0