cmrom官方中文网:多进程服务端实现

来源:百度文库 编辑:中财网 时间:2024/04/26 00:39:02

多进程服务端实现-共享socket

 来源:小明思考 - C++博客  2011-09-10

分享到: 新浪微博 腾讯微博 豆瓣网 人人网 开心网 QQ空间 搜狐微博 更多 0-

众所周知,使用多进程的服务端模型有利于程序的健壮性。传统的做法是主进程负责收发数据,然后传给子进程来处理。这种做法的缺陷是需要大量的父子进程IPC,对效率来说是一种损失。

这里,我提出另外一种比较独特的做法,就是多个进程share socket,每次进程都可以accept,然后来自己处理。

几个关键点:
1) CreateProcess使用InheritHandle标记来share socket handle
2) 通过command line直接向子进程来传递父socket的值
3)使用Global Mutext来实现子进程互斥的accept

可以改进的地方
1) 使用动态进程池来程序具有更大的伸缩性
2)监控子进程的状态,处理僵死进程

下面是一个echo server 的例子来展示这项技术, FYI

父进程(SSParent.cpp)
 

#include 
#include 
#include 
#include 

#define MUTEX_NAME "sschild"

int main(int argc, char* argv[])
{
    { //init
        WORD wVersionRequested;
        WSADATA wsaData;
        wVersionRequested = MAKEWORD( 2, 2 );
        WSAStartup( wVersionRequested, &wsaData );
    }

    SOCKET s = socket(AF_INET,SOCK_STREAM,0);
    if(s==INVALID_SOCKET)
    {
        printf("create socket failed!\n");
        return -1;
    }

    { //bind&listen
        sockaddr_in sa;
        sa.sin_family = AF_INET;
        sa.sin_port = htons( 1500 );
        sa.sin_addr.s_addr = 0 ; 
        int rc = bind(s,(sockaddr *)&sa,sizeof(sa));
        if(rc == SOCKET_ERROR)
        {
            printf("bind failed:%d\n",::WSAGetLastError());
            return -1;
        }
        listen(s,SOMAXCONN);
    }

    HANDLE hSocketMutex;
    { //create mutex
        hSocketMutex = ::CreateMutex(NULL,FALSE,MUTEX_NAME);
        if(hSocketMutex==NULL)
        {
            printf("fail CreateMutex:%d\n",::GetLastError());
            return -1;
        }
    }

    const int CHILD_NUMBER = 5;
    HANDLE hProcess[CHILD_NUMBER];
    { //create child process
       STARTUPINFO si = { sizeof(si) };
       PROCESS_INFORMATION piProcess[CHILD_NUMBER];
       char pCmdLine[256];
       sprintf(pCmdLine,"SSChild %d",s);
       for(int i=0;i       {
           if(!CreateProcess(NULL,pCmdLine,NULL,NULL,TRUE,0, NULL, NULL, &si, &piProcess[i]))
           {
               printf("fail CreateProcess:%d\n",::GetLastError());
               return -1;
           }
           hProcess[i] = piProcess[i].hProcess;
           CloseHandle(piProcess[i].hThread);
       }
    }

    ::WaitForMultipleObjects(CHILD_NUMBER,hProcess,TRUE,INFINITE);

    {//close all child handle
       for(int i=0;i       {
           CloseHandle(hProcess[i]);
       }
    }

    //clean
    CloseHandle(hSocketMutex);
    closesocket(s);
    WSACleanup( );
    return 0;
}

 

子进程(SSChild.cpp)
 

#include 
#include 
#include 
#include 

#define MUTEX_NAME "sschild"

int main(int argc, char* argv[])
{
    printf("sschild startup!\n");

    { //init
        WORD wVersionRequested;
        WSADATA wsaData;
        wVersionRequested = MAKEWORD( 2, 2 );
        WSAStartup( wVersionRequested, &wsaData );
    }

    DWORD pid = ::GetCurrentProcessId();

    HANDLE hSocketMutex;
    { //open mutex
        hSocketMutex = ::OpenMutex(MUTEX_ALL_ACCESS,FALSE,MUTEX_NAME);
        if(hSocketMutex==NULL)
        {
            printf("fail OpenMutex:%d\n",::GetLastError());
            return -1;
        }
    }

    SOCKET s;
    {  //get socket handle from cmdline
        if(argc<=1)
        {
            printf("usage: sschild socket_handle\n");
            return -1;
        }
        s = (SOCKET) atoi(argv[1]);
    }

    while(1)
    {
        WaitForSingleObject(hSocketMutex,INFINITE);
        sockaddr_in sa;
        int add_len = sizeof(sa);
        SOCKET c = accept(s,(sockaddr*)&sa,&add_len);
        ReleaseMutex(hSocketMutex);
        if(c!=INVALID_SOCKET)
        {
            printf("[%d],client:%s port:%d connected!\n",pid,inet_ntoa(sa.sin_addr),sa.sin_port);
            while(1)
            {
                char buffer[256]={0};
                int rc= recv(c,buffer,255,0);
                if(rc>0)
                {
                    printf("[%d]recv msg:%s\n",pid,buffer);
                    send(c,buffer,strlen(buffer)+1,0);
                }
                else if(rc == SOCKET_ERROR)
                {
                    printf("[%d]recv msg failed:%d\n",pid,::WSAGetLastError());
                    closesocket(c);
                    break;
                }
                else
                {
                    printf("[%d]connection close\n",pid);
                    closesocket(c);
                    break;
                }
            }
        }
        else
        {
            printf("[%d]fail accept:%d\n",pid,::WSAGetLastError());
        }
    }

    CloseHandle(hSocketMutex);
    return 0;
}