用完成端口写的echo server

2007 - 08 - 27

用完成端口写的echo server

完成端口网上的例子很多,但觉得都挺复杂的

写了一个简化版的,方便学习,也加了注释。

有任何问题,欢迎跟我讨论。

========代码来了=========

#include  < winsock2.h >
#include 
< mswsock.h >
#include 
< windows.h >

#include 
< iostream >
using   namespace  std;

int  g_ThreadCount;
HANDLE g_hIOCP 
=  INVALID_HANDLE_VALUE;
SOCKET g_ServerSocket 
=  INVALID_SOCKET;

//  Maximum Buffer Size
#define  MAX_BUFF_SIZE                8192

enum  IO_OPERATION{IO_READ,IO_WRITE};

struct  IO_DATA{
    WSAOVERLAPPED               Overlapped;
    
char                         Buffer[MAX_BUFF_SIZE];
    WSABUF                      wsabuf;
    
int                          nTotalBytes;
    
int                          nSentBytes;
    IO_OPERATION                opCode;
    SOCKET                      activeSocket;
};

DWORD WINAPI WorkerThread (LPVOID WorkThreadContext) {
    LPWSAOVERLAPPED lpOverlapped 
=  NULL;
    IO_DATA 
* lpIOContext  =  NULL; 
    WSABUF buffSend;
    DWORD dwRecvNumBytes 
=   0 ;
    DWORD dwSendNumBytes 
=   0 ;
    DWORD dwFlags 
=   0 ;
    DWORD dwIoSize 
=   0 ;
       BOOL bSuccess 
=  FALSE;
    
int  nRet  =   0 ;

       
while 1  ) {
         
void   *  lpCompletionKey  =  NULL;
         bSuccess 
=  GetQueuedCompletionStatus(g_hIOCP,  & dwIoSize,
                                             (LPDWORD)
& lpCompletionKey,
                                             (LPOVERLAPPED 
* ) & lpOverlapped, 
                                             INFINITE);
         
if ! bSuccess )
         {
            cout 
<<   " GetQueuedCompletionStatus() failed: " << GetLastError() << endl;
            
break ;
         }

         lpIOContext 
=  (IO_DATA  * )lpOverlapped;

         
if (dwIoSize  ==   0 // socket closed?
         {
             cout 
<<   " Client disconnect "   <<  endl;
             closesocket(lpIOContext
-> activeSocket);
             delete lpIOContext;
             
continue ;
         }

         
if (lpIOContext -> opCode  ==  IO_READ)  //  a read operation complete
         {
                lpIOContext
-> nTotalBytes   =  lpIOContext -> wsabuf.len;
                lpIOContext
-> nSentBytes    =   0 ;
                lpIOContext
-> opCode  =  IO_WRITE;
                dwFlags 
=   0 ;
                nRet 
=  WSASend(
                              lpIOContext
-> activeSocket,
                              
& lpIOContext -> wsabuf,  1 & dwSendNumBytes,
                              dwFlags,
                              
& (lpIOContext -> Overlapped), NULL);
                
if ( nRet  ==  SOCKET_ERROR  &&  (ERROR_IO_PENDING  !=  WSAGetLastError()) ) {
                        cout 
<<   " WASSend Failed::Reason Code:: " <<  WSAGetLastError()  <<  endl;
                        closesocket(lpIOContext
-> activeSocket);
                        delete lpIOContext;
                        
continue ;
                }
         }
         
else   if (lpIOContext -> opCode  ==  IO_WRITE)  // a write operation complete
         {
                lpIOContext
-> nSentBytes   +=  dwIoSize;
                dwFlags 
=   0 ;
                
if ( lpIOContext -> nSentBytes  <  lpIOContext -> nTotalBytes ) {
                    lpIOContext
-> opCode  =  IO_WRITE;
                    
//  A Write operation has not completed yet, so post another
                    
//  Write operation to post remaining data.
                    buffSend.buf  =  lpIOContext -> Buffer  +  lpIOContext -> nSentBytes;
                    buffSend.len 
=  lpIOContext -> nTotalBytes  -  lpIOContext -> nSentBytes;
                    nRet 
=  WSASend (
                                   lpIOContext
-> activeSocket,
                                   
& buffSend,  1 & dwSendNumBytes,
                                   dwFlags,
                                   
& (lpIOContext -> Overlapped), NULL);

                    
if ( nRet  ==  SOCKET_ERROR  &&  (ERROR_IO_PENDING  !=  WSAGetLastError()) ) {
                        cout 
<<   " WASSend Failed::Reason Code:: " <<  WSAGetLastError()  <<  endl;
                        closesocket(lpIOContext
-> activeSocket);
                        delete lpIOContext;
                        
continue ;
                    }
                } 
else  {
                    
//  Write operation completed, so post Read operation.
                    lpIOContext -> opCode  =  IO_READ; 
                    dwRecvNumBytes 
=   0 ;
                    dwFlags 
=   0 ;
                    lpIOContext
-> wsabuf.buf  =  lpIOContext -> Buffer,
                    ZeroMemory(lpIOContext
-> wsabuf.buf,MAX_BUFF_SIZE);
                    lpIOContext
-> Overlapped.Internal  =   0 ;
                    lpIOContext
-> Overlapped.InternalHigh  =   0 ;
                    lpIOContext
-> Overlapped.Offset  =   0 ;
                    lpIOContext
-> Overlapped.OffsetHigh  =   0 ;
                    lpIOContext
-> Overlapped.hEvent  =  NULL;
                    lpIOContext
-> wsabuf.len  =  MAX_BUFF_SIZE;
                    nRet 
=  WSARecv(
                                  lpIOContext
-> activeSocket,
                                  
& lpIOContext -> wsabuf,  1 & dwRecvNumBytes,
                                  
& dwFlags,
                                  
& lpIOContext -> Overlapped, NULL);
                    
if ( nRet  ==  SOCKET_ERROR  &&  (ERROR_IO_PENDING  !=  WSAGetLastError()) ) {
                        cout 
<<   " WASRecv Failed::Reason Code:: " <<  WSAGetLastError()  <<  endl;
                        closesocket(lpIOContext
-> activeSocket);
                        delete lpIOContext;
                        
continue ;
                    } 
                }
         }
    }
    
return   0 ;
}

void  main ( int  argc,  char   *  argv[])
{
    { 
//  Init winsock2
        WSADATA wsaData;
        ZeroMemory(
& wsaData, sizeof (WSADATA));
        
int  retVal  =   - 1 ;
        
if ( (retVal  =  WSAStartup(MAKEWORD( 2 , 2 ),  & wsaData))  !=   0  ) {
            cout 
<<   " WSAStartup Failed::Reason Code:: " <<  retVal  <<  endl;
            
return ;
        }
    }

    {  
// Create socket
        g_ServerSocket  =  WSASocket(AF_INET,SOCK_STREAM, IPPROTO_TCP, NULL, 0 ,WSA_FLAG_OVERLAPPED);

        
if ( g_ServerSocket  ==  INVALID_SOCKET ) {
            cout 
<<   " Server Socket Creation Failed::Reason Code:: "   <<  WSAGetLastError()  <<  endl;
            
return ;
        }
    }

    {   
// bind
        sockaddr_in service;
        service.sin_family 
=  AF_INET;
        service.sin_addr.s_addr 
=  htonl(INADDR_ANY);
        service.sin_port 
=  htons( 5000 );
        
int  retVal  =  bind(g_ServerSocket,(SOCKADDR  * ) & service, sizeof (service));
        
if ( retVal  ==  SOCKET_ERROR ) {
            cout 
<<   " Server Soket Bind Failed::Reason Code:: " <<  WSAGetLastError()  <<  endl;
            
return ;
        }
    }

    {   
// listen
         int  retVal  =  listen(g_ServerSocket,  8 );
        
if ( retVal  ==  SOCKET_ERROR ) {
            cout 
<<   " Server Socket Listen Failed::Reason Code:: " <<  WSAGetLastError()  <<  endl;
            
return ;
        }
    }

    {   
//  Create IOCP
        SYSTEM_INFO sysInfo;
        ZeroMemory(
& sysInfo, sizeof (SYSTEM_INFO));
        GetSystemInfo(
& sysInfo);
        g_ThreadCount 
=  sysInfo.dwNumberOfProcessors  *   1 ;
        g_hIOCP 
=  CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL, 0 ,g_ThreadCount);
        
if  (g_hIOCP  ==  NULL) {
            cout 
<<   " CreateIoCompletionPort() Failed::Reason:: " <<  GetLastError()  <<  endl;
            
return ;            
        }

           
if  (CreateIoCompletionPort((HANDLE)g_ServerSocket,g_hIOCP, 0 , 0 ==  NULL){
            cout 
<<   " Binding Server Socket to IO Completion Port Failed::Reason Code:: " <<  GetLastError()  <<  endl;
            
return  ;    
        }
    }

    {  
// Create worker threads
         for ( DWORD dwThread = 0 ; dwThread  <  g_ThreadCount; dwThread ++  )
        {
            HANDLE  hThread;
            DWORD   dwThreadId;

            hThread 
=  CreateThread(NULL,  0 , WorkerThread,  0 0 & dwThreadId);
            CloseHandle(hThread);
        }
    }

    { 
// accept new connection
         while ( 1 )
        {
            SOCKET ls 
=  accept( g_ServerSocket, NULL, NULL );
            
if (ls  ==  SOCKET_ERROR)   break ;
            cout 
<<   " Client connected. "   <<  endl;

            { 
// diable buffer to improve performance
                 int  nZero  =   0 ;
                setsockopt(ls, SOL_SOCKET, SO_SNDBUF, (
char   * ) & nZero,  sizeof (nZero));
            }

            
if  (CreateIoCompletionPort((HANDLE)ls,g_hIOCP, 0 , 0 ==  NULL){
                cout 
<<   " Binding Client Socket to IO Completion Port Failed::Reason Code:: " <<  GetLastError()  <<  endl;
                closesocket(ls);
            }
            
else  {  // post a recv request
                IO_DATA  *  data  =   new  IO_DATA;
                ZeroMemory(
& data -> Overlapped, sizeof (data -> Overlapped));
                ZeroMemory(data
-> Buffer, sizeof (data -> Buffer));
                data
-> opCode  =  IO_READ;
                data
-> nTotalBytes  =   0 ;
                data
-> nSentBytes   =   0 ;
                data
-> wsabuf.buf   =  data -> Buffer;
                data
-> wsabuf.len   =   sizeof (data -> Buffer);
                data
-> activeSocket  =  ls;
                DWORD dwRecvNumBytes
= 0 ,dwFlags = 0 ;
                
int  nRet  =  WSARecv(ls, & data -> wsabuf,  1 & dwRecvNumBytes,
                                  
& dwFlags,
                                  
& data -> Overlapped, NULL);
                
if (nRet  ==  SOCKET_ERROR   &&  (ERROR_IO_PENDING  !=  WSAGetLastError())){
                    cout 
<<   " WASRecv Failed::Reason Code:: " <<  WSAGetLastError()  <<  endl;
                    closesocket(ls);
                    delete data;
                }
            }
        }
    }

    closesocket(g_ServerSocket);
    WSACleanup();
}

你可能感兴趣的:(用完成端口写的echo server)