Натолкнулся на странную ошибку с IOCP, при выполнении некоторых вызовов WSARecv происходит Access Violation внутри системного кода, после этого socket не работает. Вот здесь
http://www.rsdn.ru/forum/network/3441036.1.aspxАвтор: Armastab
Дата: 24.06.09
, нечто подобное уже обсуждалось, но решения так и не было.
Ниже минимальный код сервера на котором эта ошибка воспроизводится, один поток, сервер накапливает "пакеты" по 3 байта. С качестве клиента, можно использовать обычный telnet на порт 3030. Ошибка возникает когда переданный с клиента кусок больше чем тот который сервер ожидает в данный момент. Шаги для воспроизведения: заходим через telnet mycomp 3030, сервер просит 3 байта, нажимает любую букву, 1 байт передаётся на сервер, сервер получает 1 байт и ждет 2 байта, нажимаем функциональную клавишу (F1), на сервер передаётся 3 байта, сервер получает 2 байта, следующий вызов WSARecv приводит к ошибке.
WDYT?
#include <winsock2.h>
#include <tchar.h>
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
SOCKET ListenSocket, AcceptSocket;
struct sockaddr_in saClient;
int iClientSize = sizeof(saClient);
u_short port = 3030;
char* ip;
sockaddr_in service;
int error;
error = WSAStartup(MAKEWORD(2,2), &wsaData);
if (error)
return -1;
ListenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (ListenSocket == INVALID_SOCKET)
return -1;
service.sin_family = AF_INET;
service.sin_port = htons(port);
hostent* thisHost;
thisHost = gethostbyname("");
ip = inet_ntoa (*(struct in_addr *)*thisHost->h_addr_list);
service.sin_addr.s_addr = inet_addr(ip);
error = bind(ListenSocket, (SOCKADDR *) &service, sizeof(SOCKADDR));
if (error == SOCKET_ERROR)
return -1;
error = listen(ListenSocket, 1);
if (error == SOCKET_ERROR)
return -1;
AcceptSocket = WSAAccept(ListenSocket, (SOCKADDR*) &saClient, &iClientSize, NULL, NULL);
HANDLE CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
CreateIoCompletionPort((HANDLE)AcceptSocket, CompletionPort, 0, 0);
size_t nDataSize = 3;
size_t nDataComplete = 0;
char pszData[256];
while (true)
{
if (nDataComplete >= nDataSize)
{
printf("---\n");
nDataComplete = 0;
}
WSABUF Buffer;
Buffer.buf = pszData + nDataComplete;
Buffer.len = nDataSize - nDataComplete;
WSAOVERLAPPED Overlapped;
ZeroMemory(&Overlapped, sizeof(Overlapped));
DWORD nFlags = 0;
if (!WSARecv(AcceptSocket, &Buffer, 1, NULL, &nFlags, &Overlapped, NULL))
return -1;
DWORD nError;
DWORD nBytesTransferred;
WSAOVERLAPPED* pOverlapped = NULL;
while (true)
{
DWORD nKey;
if (!::GetQueuedCompletionStatus(CompletionPort, &nBytesTransferred, &nKey, &pOverlapped, 0))
{
nError = ::GetLastError();
if (nError == WAIT_TIMEOUT)
continue;
return -1;
}
else
{
nError = ::GetLastError();
if (nError == ERROR_IO_PENDING)
continue;
break;
}
}
nDataComplete += nBytesTransferred;
printf("%i\n", nBytesTransferred);
}
closesocket(AcceptSocket);
closesocket(ListenSocket);
WSACleanup();
return 0;
}