用完成端口写的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)