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


众所周知,使用多进程的服务端模型有利于程序的健壮性。传统的做法是主进程负责收发数据,然后传给子进程来处理。这种做法的缺陷是需要大量的父子进程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  < stdio.h >
#include 
< winsock2.h >
#include 
< windows.h >
#include 
< process.h >

#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 < CHILD_NUMBER; ++ 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 < CHILD_NUMBER; ++ i)
       {
           CloseHandle(hProcess[i]);
       }
    }

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

 

子进程(SSChild.cpp)

#include  < stdio.h >
#include 
< winsock2.h >
#include 
< windows.h >
#include 
< process.h >

#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 ;
}

你可能感兴趣的:(多进程服务端实现-共享socket)