WinSock2 IOCP WSARecv GetQueuedCompletionStatus: данные (автоматически) попадают в буфер char *, а не в WSABUF.buf … почему?

Во время отладки, когда вызывается WSARecv, я предоставляю функции адрес PerIoData-> WSABUF состав. Это должно назначить отправленные данные WSABUF.buf char * массив, который кажется. Когда рабочий поток возвращается к ожиданию GetQueuedCompletionStatus, кажется, что каким-то (волшебным образом) образом эти данные отправляются в PerIoData.Buffer (массив *). По сути, PerIoData.Buffer а также PerIoData.WSABUF.buf оба равны одному и тому же массиву char *. Когда я удаляю PerIoData.Buffer от PER_IO_DATA Структура (и все ссылки на нее), GetQueuedCompletionStaus никогда не возвращается, когда клиент отправляет данные, хотя я знаю WSABUF.buf должны быть заполнены данными.

Соответствующая информация:

  1. Я реализую модель порта завершения, описанную в разделе «Сетевое программирование для Microsoft Windows» (стр. 157). Хотя примеры из этой книги оставляют много интересного для самостоятельного изучения, мой код теперь работает нормально.
  2. В цикле while объекта ServerWorkerThread: вызываемый первым 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-> Буфер все же кажется, что он всегда заполняется отправленными данными. Я уверен, что GetQueuedCompletionStatus «знает», чтобы отправить эти данные PerIoData-> Буфер хотя он ожидает указатель на LPOVERLAPPED структура (которой я передаю PerIoData экземпляр структуры, содержащий буфер массив символов в вопросе). Это действительно беспокоит меня … Может быть, это не так, как я думаю, но единственное место, где я могу увидеть PerIoData-> Буфер заселен изнутри GetQueuedCompletionStatus метод. Если это не так, то PerIoData-> Буфер кажется населенный из ниоткуда? Я искал MSDN и Google в течение нескольких дней. Я продолжу искать и, если найду ответ, выложу обновление. Пожалуйста помоги? Заранее спасибо!

* Примечание: я бы создал теги WSABUF и GetQueuedCompletionStatus, но это мой первый пост.

—РЕДАКТИРОВАТЬ: Я публикую структуры и рабочий поток, исключая все другие не связанные с ним код .—
Вы заметите, что _PER_IO_DATA :: DataBuf.buf выделяется память, а затем обнуляется. Не указывая на массив 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;
}

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]