windows下iocp的简单代码

//////server

#include <WinSock2.h>

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

#include <process.h>



//该例子代码在并发情况下存在问题,需要对clientRecord进行mutex保护才能保证操作的有效性。



#define HOST_PORT                   10000

#define MAX_BUFF_SIZE               8192





typedef struct msg_watch_para_struct msg_watch_para_t;

struct msg_watch_para_struct {

    HANDLE      cp;

};



typedef struct wsa_data_struct wsa_data_t;

struct wsa_data_struct {

    WSAOVERLAPPED               Overlapped;



    char                        Buffer[MAX_BUFF_SIZE];

    WSABUF                      wsabuf;

    int                         nTotalBytes;

    int                         nSentBytes;

    SOCKET                      SocketAccept; 

};



typedef struct port_info_struct port_info_t;

struct port_info_struct {

    int         client_socket;

    wsa_data_t  *pIOContext;

};



void CALLBACK CompletionROUTINE(

  IN DWORD dwError, 

  IN DWORD cbTransferred, 

  IN LPWSAOVERLAPPED lpOverlapped, 

  IN DWORD dwFlags

)

{

    //仅仅是为了看lpOverlapped的值

    wsa_data_t      *was_data = (wsa_data_t*)lpOverlapped;

}





//接收线程

unsigned

__stdcall

msg_watch_thread(void*   p)

{

    msg_watch_para_t    *para = (msg_watch_para_t*)p;

    port_info_t         *port_info;

    char                buf[1024 * 11];

    LPWSAOVERLAPPED     lpOverlapped = NULL;

    wsa_data_t          *was_data;



    BOOL bSuccess = FALSE;

    DWORD dwIoSize = 0;



    while (1)

    {

        bSuccess = GetQueuedCompletionStatus(para->cp, &dwIoSize,

                                                (PDWORD_PTR)&port_info,

                                                &lpOverlapped, 

                                                INFINITE);

        if (!bSuccess)

        {

            DWORD ecode = GetLastError();

        }



        was_data = (wsa_data_t*)lpOverlapped;



        {

            DWORD dwRecvNumBytes = 0;     

            int nRet = 0;

            DWORD dwFlags = 0;

            while (TRUE)

            {

                nRet = WSARecv(port_info->client_socket, &(port_info->pIOContext->wsabuf), 

                                1, &dwRecvNumBytes, &dwFlags,

                                &(port_info->pIOContext->Overlapped), NULL);

                if( nRet == SOCKET_ERROR  ) 

                {

                    if ((ERROR_IO_PENDING != WSAGetLastError()))    //数据读取完成

                        break;



                    //出现其他错误,关闭端口,干掉session

                    printf("WSARecv() Failed: %d\n", WSAGetLastError());

                }

            }

            buf[1023] = 0;

            send(port_info->client_socket, buf, 1024, 0);

        }

    }



    return 0;

}



int main()

{

    WORD wVersionRequested;

    WSADATA wsaData;

    int err;

    msg_watch_para_t    watch_para;





    wVersionRequested = MAKEWORD( 2, 2 );



    err = WSAStartup( wVersionRequested, &wsaData );



    if ( err != 0 )

    {

        /* Tell the user that we could not find a usable */

        /* WinSock DLL.                                  */

        return 0;

    }



    /* Confirm that the WinSock DLL supports 2.2.*/

    /* Note that if the DLL supports versions greater    */

    /* than 2.2 in addition to 2.2, it will still return */

    /* 2.2 in wVersion since that is the version we      */

    /* requested.                                        */

    if ( LOBYTE( wsaData.wVersion ) != 2 ||

            HIBYTE( wsaData.wVersion ) != 2 )

    {

        /* Tell the user that we could not find a usable */

        /* WinSock DLL.                                  */

        WSACleanup( );

        return 0;

    }



    int servfd, clientfd;



    //servfd = socket(AF_INET, SOCK_STREAM, 0);

    servfd = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);



    if(servfd < 0)

    {

        printf("server create socket failed.\n");



        return 0;

    }



    int on = 1;



    if(setsockopt(servfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)) < 0)

    {

        printf("set socket option failed.\n");



        return 0;

    }



    struct sockaddr_in servaddr;



    struct sockaddr_in clientaddr;



    memset(&servaddr,0,sizeof(servaddr));



    memset(&clientaddr,0,sizeof(clientaddr));



    servaddr.sin_family = AF_INET;



    servaddr.sin_port = htons(HOST_PORT);



    servaddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);



    if(bind(servfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)

    {

        printf("bind failed.\n");

        return 0;

    }



    if(listen(servfd,10) < 0)

    {

        printf("listen failed.\n");

        return 0;

    }



    int length = sizeof(clientaddr);



    watch_para.cp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 10);



    //创建消息事件处理线程

    _beginthreadex((void*)NULL,

                       1024 * 512,

                       msg_watch_thread, 

                       &watch_para,

                       0,

                       NULL);





    for(;;)

    {

        HANDLE      cp;

        port_info_t *port_info;

        //接收用户连接

        //clientfd = accept(servfd, (struct sockaddr *)&clientaddr,&length);

        clientfd = WSAAccept(servfd, NULL, NULL, NULL, 0);

        if ( clientfd == SOCKET_ERROR ) 

        {

            printf("socket error.\n");

        }



        //初始化端口

        port_info = (port_info_t*)malloc(sizeof(port_info_t));

        port_info->pIOContext = (wsa_data_t*)malloc(sizeof(wsa_data_t));

        {

            port_info->client_socket = clientfd;

            port_info->pIOContext->Overlapped.Internal = 0;

            port_info->pIOContext->Overlapped.InternalHigh = 0;

            port_info->pIOContext->Overlapped.Offset = 0;

            port_info->pIOContext->Overlapped.OffsetHigh = 0;

            port_info->pIOContext->Overlapped.hEvent = NULL;

            port_info->pIOContext->nTotalBytes = 0;

            port_info->pIOContext->nSentBytes  = 0;

            port_info->pIOContext->wsabuf.buf  = port_info->pIOContext->Buffer;

            port_info->pIOContext->wsabuf.len  = sizeof(port_info->pIOContext->Buffer);

        }



        //将端口加入iocp的数组

        cp = CreateIoCompletionPort((HANDLE)clientfd, watch_para.cp, (ULONG_PTR)port_info, 0);

        if (cp == INVALID_HANDLE_VALUE)

        {

            DWORD ecode = GetLastError();

        }



        {

            DWORD dwRecvNumBytes = 0;     

            int nRet = 0;

            DWORD dwFlags = 0;

            nRet = WSARecv(clientfd, &(port_info->pIOContext->wsabuf), 

                            1, &dwRecvNumBytes, &dwFlags,

                            &(port_info->pIOContext->Overlapped), NULL);

            if( nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError()) ) 

            {

                printf("WSARecv() Failed: %d\n", WSAGetLastError());

            }

        }

    }



    closesocket(servfd);



    return 0;

}

只是简单的服务器端iocp的代码实现。msg_watch_thread函数完成消息的接收,这个结构设计的目的是使用专门的线程获得消息事件,但本身并不处理消息事件的内容,再次生成任务抛出,由其他的线程进行消息的处理。通过该种方式简化线程工作内容,使不同的线程专注于某个特定领域的工作,每个iocp的对象只需要一个线程进行对应,如果端口较多,并发量一个线程无法承担,则可以增加新的消息监视线程。

不过这种模型下,任务的生成可能成为处理的瓶颈。任务加入队列和从队列中取出将被多个线程争用。不过可以通过将任务的分成多个不同类型的队列,使用多组队列达到并发的效果。

你可能感兴趣的:(windows)