1

デバッグ中に WSARecv が呼び出されると、関数にPerIoData->WSABUF構造体のアドレスを指定します。これにより、送信されたデータがWSABUF.buf char* 配列に割り当てられるようになります。ワーカースレッドが待機中のGetQueuedCompletionStatusにループバックすると、どういうわけか (魔法のように) そのデータが PerIoData.Buffer (char* 配列) に送信されるように見えます。したがって、基本的に、PerIoData.BufferPerIoData.WSABUF.bufは両方とも同じ char* 配列に等しくなります。PER_IO_DATA構造体(およびそれへのすべての参照)からPerIoData.Bufferを削除すると、GetQueuedCompletionStausは、クライアントがデータを送信しても返されませんが、WSABUF.bufにデータを入力する必要があります。

関連情報:

  1. 「Microsoft Windows のネットワーク プログラミング」(p.157) にある Completion Port Model を実装しています。その本の例は、個別に発見する必要がありましたが、私のコードは今では正常に動作します。
  2. ServerWorkerThread の while ループ: 最初に呼び出される GetQueuedCompletionStatus は、per_handle_data と per_io_data を受け取ります。
  3. per_io_data 構造体は次のとおりです。

    struct _PER_IO_DATA{ //in the interests of an efficient question, i'm omitting the
    //constructor/destructor code
    public:
        OVERLAPPED Overlapped;
        WSABUF DataBuf;
        char myBuffer[BUFFER_LENGTH];
        int BufferLen;
        int OperationType;
    };
    typedef _PER_IO_DATA PER_IO_DATA;
    typedef _PER_IO_DATA *PPER_IO_DATA;
    
  4. 私の GetQueuedCompletionStatus 関数は次のように呼び出されます。

    ret = GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (LPDWORD)&PerHandleData, (LPOVERLAPPED *)&PerIoData, INFINITE);

  5. 私の WSARecv 関数は次のように呼び出されます。

    WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, NULL, &Flags, ((LPWSAOVERLAPPED)&PerIoData->Overlapped), NULL); //i know casting the Overlapped structure as LPWSAOVERLAPPED is unnecessary, but I was tweaking the //code when I didn't fully understand the problems I was having.

私の問題は、PerIoData->Bufferに明示的に何かを割り当てることはありませんが、送信されたデータが常に読み込まれるように見えることです。GetQueuedCompletionStatus は、このデータをそのPerIoData->Bufferに送信することを「知っている」と信じていますが、 LPOVERLAPPED構造体へのポインターを期待しています(これに、問題のBuffer char 配列を含むPerIoData構造体インスタンスを渡します)。それは本当に私を悩ませています...たぶん、私が考えているように動作していないかもしれませんが、PerIoData->Bufferが読み込まれているのを見ることができる唯一の場所は、 GetQueuedCompletionStatusメソッド内からです。そうでない場合は、PerIoData->Bufferどこからともなく密集しているように見える?私は何日も MSDN と google を精査してきました。探し続けて、答えが見つかったら更新を投稿します。助けてください?前もって感謝します!

*注意: タグ WSABUF と GetQueuedCompletionStatus を作成したかったのですが、これが初めての投稿です。

-- 編集: 構造体とワーカー スレッドを掲載していますが、関連のない他のコードはすべて 除外しています。myBuffer 配列を指していない....

#include "stdafx.h"
#define SEND_POSTED 1
#define RECV_POSTED 2
#define BUFFER_LENGTH 1024

HANDLE CompletionPort;
SOCKADDR_IN serverAddress, *clientAddress;
SOCKET listener, client;
unsigned short port = 5000;
SYSTEM_INFO SystemInfo;
int i;

struct _PER_HANDLE_DATA{//Per handle data structure
    SOCKET Socket;
    SOCKADDR_STORAGE Address;
    _PER_HANDLE_DATA(){
        Socket = 0;
        ZeroMemory(&Address, sizeof(SOCKADDR_STORAGE));
    }
    ~_PER_HANDLE_DATA(){
        Socket = NULL;
        ZeroMemory(&Address, sizeof(SOCKADDR_STORAGE));
    }
};typedef _PER_HANDLE_DATA PER_HANDLE_DATA;typedef _PER_HANDLE_DATA *PPER_HANDLE_DATA;


struct _PER_IO_DATA{
public:
    OVERLAPPED Overlapped;
    WSABUF DataBuf;
    char myBuffer[BUFFER_LENGTH];
    int BufferLen;
    int OperationType;
    _PER_IO_DATA(){
        OperationType = 0;
        DataBuf.len = BUFFER_LENGTH;
        DataBuf.buf = (char*)malloc(BUFFER_LENGTH+1);
        BufferLen = BUFFER_LENGTH;
        ZeroMemory(DataBuf.buf, (sizeof(BUFFER_LENGTH+1)));
        ZeroMemory(&myBuffer, (sizeof(char)*BUFFER_LENGTH));
        SecureZeroMemory((PVOID)&Overlapped, sizeof(Overlapped));
    }
    ~_PER_IO_DATA(){
        free(&DataBuf.buf);
    }
};
typedef _PER_IO_DATA PER_IO_DATA;
typedef _PER_IO_DATA *PPER_IO_DATA;


unsigned _stdcall ServerWorkerThread(LPVOID CompletionPortID);

int _tmain(int argc, _TCHAR* argv[])
{
    /*
        INITIALIZE WINSOCK AND COMPLETION PORT, AND ACCEPT CONNECTIONS
    */
}

unsigned _stdcall ServerWorkerThread(LPVOID CompletionPortID){
    printf("ServerWorkerThread(%d) Working\n", GetCurrentThreadId());
    HANDLE CompletionPort = (HANDLE) CompletionPortID;
    DWORD BytesTransferred;
    PPER_HANDLE_DATA PerHandleData = new PER_HANDLE_DATA;
    PPER_IO_DATA PerIoData = new PER_IO_DATA;
    DWORD SendBytes = 0, RecvBytes = 0;
    DWORD Flags;
    BOOL ret;
    Sleep(2000);
    while(TRUE){
        ret = GetQueuedCompletionStatus(CompletionPort,
            &BytesTransferred,
            (LPDWORD)&PerHandleData,
            (LPOVERLAPPED *)&PerIoData,
            INFINITE);
        //printf("\n\nBytesTransferred: %d\n\n", BytesTransferred);
        if(BytesTransferred == 0 && (PerIoData->OperationType == RECV_POSTED || PerIoData->OperationType == SEND_POSTED)){
            closesocket(PerHandleData->Socket);
            GlobalFree(PerHandleData);
            GlobalFree(PerIoData);
            continue;
        }
        if(PerIoData->OperationType == RECV_POSTED){
        //output received data
            if(!strcmp(PerIoData->DataBuf.buf, "Disconnect") || !strcmp(PerIoData->DataBuf.buf, "disconnect")){
                printf("Disconnecting...\n");
                if(!shutdown(PerHandleData->Socket, SD_BOTH)){
                    closesocket(PerHandleData->Socket);
                    delete(PerHandleData);
                }
            }else{
                printf("RECV_POSTED: %s\n", PerIoData->DataBuf.buf);
            }
        }
        Flags = 0;

        SecureZeroMemory((PVOID)&PerIoData->Overlapped, sizeof(WSAOVERLAPPED));
        PerIoData->DataBuf.len = BUFFER_LENGTH;
        //***************************************************************************
        //Even though the following is commented out, PerIoData->DataBuf.buf 
        //is still being populated and so is PerIoData-myBuffer
        //So why is myBuffer being populated with data when DataBuf.buf is not pointing to it??
        //PerIoData->DataBuf.buf = PerIoData->myBuffer;
        //Also, if you comment out all references of myBuffer, GetQueuedCompletionStatus(),
        //will never return if myBuffer doesn't exist...how does it seem to be 'aware' of myBuffer?
        //***************************************************************************
        PerIoData->OperationType = RECV_POSTED;
        WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, NULL, &Flags, ((LPWSAOVERLAPPED)&PerIoData->Overlapped), NULL);
    }
    return 0;
}
4

0 に答える 0