• 2006-11-27

    8.2.4 重叠模型 - [多线程程序设计]

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://xingzhesun.blogbus.com/logs/3921200.html

    8.2.4 重叠模型
    s = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
    1.事件通知 将win32事件对象与WSAOVERLAPPED结构关联在一起。
    typedef struct WSAOVERLAPPED
    {
    DWORD Internal;
    DWORD InternalHigh;
    DWORD offset;
    DWORD OffsetHigh;
    WSAEVENT hEvent;
    } WSAOVERLAPPED, FAR*LPWSAOVERLAPPED;
    hEvent 它允许应用程序将一个事件对象句柄同一个套接字关联起来。

    BOOL WSAGetOverlappedResult(SOCKET S, LPWSAOVERLAPPED lpOverlapped, LPDWORD lpcbTransfer, BOOL fWari, LPDWORD lpdwFlags);
    void main()
    {
    WSABUF DataBuf;
    DWORD EventTotal = 0;
    WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
    WSAOVERLAPPED AcceptOverlapped;
    SOCKET ListenSocket, AcceptSocket;

    //step 1
    //start winsock and set up a listening socket

    //step 2
    //accepte an inbound connection

    AcceptSocket = accept(ListenSocket, NULL, NULL);

    //step 3
    //set up an overlapped structure

    EventArray[EventTotal]=WSACreateEvent();
    ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));

    AcceptOverlapped.hEvent = EventArray[EventTotal];

    DataBuf.len = DATA_BUFSIZE;
    DataBuf.buf = buffer;

    EventTotal++;

    //step 4;
    //post a WSARecv request to begin receiving data on the socket.
    WSARecv(AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped, NULL);

    //Process overlapped receives on the socket.
    while (TRUE)
    {
    //step 5
    //wait for overlapped io call to complete
    Index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);

    //Index should be 0 because we have one event handle in eventarray.

    //step 6
    //reset the signaled event
    WSAResetEvent(EventArray[Index - WSA_WAIT_EVENT_0]);

    //step 7
    //Determine the status of the overlapped request.
    WSAGetOverlappedResult(AcceptSocket, &AcceptOverlapped, &BytesTransferred, FALSE, &Flags);

    //First check to see whether the peer has closed the connection ,and if so , close the socket.
    if (BytesTransferred == 0)
    {
    printf("Closing socket %d\n", AcceptSocket);
    closesocket(AcceptSocket);
    WSACloseEvent(Index - WSA_WAIT_EVENT_0);
    return;
    }

    //Do something with the received data DataBuf contains the received data.
    ...

    //step 8
    //post another WSARecv() request on the socket

    Flags = 0;
    ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));

    AcceptOverlapped.hEvent = EventArray[Index - WSA_WAIT_EVENT_0];

    DataBuf.len = DATA_BUFSIZE;
    DataBuf.buf = Buffer;

    WSARecv(AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped, NULL);
    }
    }

    2.完成例程
    在一个重叠IO请求完成时由系统调用的函数。他们的基本设计宗旨是通过调用者的线程,为一个已完成的I请求提供服务。除此之外,应用程序可通过完成例程,继续进行重叠IO处理。
    void CALLBACK CompletionROUTINE(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags);

    WSABUF DataBuf;
    SOCKET AcceptSocket;

    void main()
    {
    WSAOVERLAPPED Overlapped;

    //step 1
    //start winsock and set up a listening socket

    //step 2
    //accept a new connection
    AcceptSocket = accept(ListenSocket, NULL, NULL);


    //step 3
    //To get the overlapped IO processing started, first submit an overlapped WSARecv() request.

    Flags = 0;
    ZeroMemory(&Overlapped, sizeof(WSAOVERLAPPED));

    DataBuf.len = DATA_BUFSIZE;
    DataBuf.buf = buffer;

    EventTotal++;

    //step 4;
    //post a WSARecv request to begin receiving data on the socket.
    if(WSARecv(AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped, WorkerRoutine)==SOCKET_ERROR)
    {
    if (WSAGetLastError()!=WSA_IO_PENDING)
    {
    printf("WSARecv() failed with error%d\n",WSAGetLastError());
    return;
    }
    }

    //since the WSAWaitForMutipleEvents()API requires waiting on one or more event objects, we will have to create a dummy event object, Aa
    //an alterative , we can use SleepEx() instead.
    EventArray[0]=WSACreateEvent();

    while (TRUE)
    {
    //step 5
    Index = WSAWaitForMultipleEvents(1,EventArray, FALSE, WSA_INFINITE, FALSE);

    //step 6
    if (Index == WAIT_IO_COMPLETION)
    {
    //An overlapped request completion routine just completed ,continue servicing more completion rountines.
    }
    else
    {
    //A bad error occurred --stop processing! if we were also processing an event object, this could be index to the event array.

    return;
    }
    }
    }

    void CALLBACK WorkerRoutine(DWORD Error, DWORD BytesTransferred, LPWSAOVERLAPPED Overlapped, DWORD InFlags)
    {
    DWORD SendBytes, RecvBytes;
    DWORD Flags;
    if (Error !=0)||BytesTransferred ==0
    {
    //Either a bad error occurred on the socket or the socket was closed by peer closesocket(AcceptSocket);
    return;
    }

    //At this point, an overlapped WSARecv() request completed successfully. Now we can retrieve the received data that is contained in the variable DataBuf
    //After processing the received data, we need to post another overlapped WSARecv() or WSASend() request. For simplicity , we will post another WSARecv() requst.
    Flags = 0;
    ZeroMemory(&Overlapped,sizeof(WSAOVERLAPPED));

    DataBuf.len = DATA_BUFSIZE;
    DataBuf.buf = Buffer;

    if (WSARecv(AcceptSocket, &DataBuf,1,&RecvBytes,&Flags, &Overlapped, WorkerRoutine)==SOCKET_ERROR)
    {
    if (WSAGetLastError()!=WSA_IO_PENDING)
    {
    printf("failed with error%d\n",WSAGetLastError());
    return;
    }
    }
    }


    随机文章:

    第三章 邮槽 2006-11-17

    收藏到:Del.icio.us