IO完成端口和WSASend

IO Completion Ports and WSASend

本文关键字:WSASend IO      更新时间:2024-09-22

很抱歉,但请解释如何将IOCP与WSASend一起使用-例如,向服务器发送一条简单的消息并从服务器接收响应。

我在做这个:

  1. 创建完成端口
  2. 为完成端口创建线程
  3. 我创建了一个带有Overlapped标志的WSASocket
  4. 我使用WSAConnect与远程服务器建立连接
  5. 我将套接字绑定到完成端口
  6. 我通过调用WSASend函数向服务器发送一条消息

像这样:

void My_func_for_Thread(HANDLE iocp)
{
DWORD my_DWORD;
PULONG_PTR   my_CompletionKey;
WSAOVERLAPPED* my_WSAOVERLAPPED_1;

int my_GetLastError;

while (1)
{
BOOL my_BOOL_GetQueuedCompletionStatus = GetQueuedCompletionStatus(iocp, &my_DWORD, my_CompletionKey, &my_WSAOVERLAPPED_1, INFINITE);

my_GetLastError = GetLastError();

if (my_BOOL_GetQueuedCompletionStatus == FALSE)
{
std::cout << "GetQueuedCompletionStatus== FALSE" << std::endl;
}
}
}

int main()
{

//-------------------------------------------------------------------Create port IO-------------------------------------------------------------

int Number_Threads = 4;  

HANDLE My_handle_IOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, Number_Threads);

//------------------------------------------------------------------------------------------------------------------------------------------------



//-------------------------------------------------------------------Create thread for IOCP-------------------------------------------------------

std::vector<HANDLE>my_vector_Thread;


for (int i = 0; i < Number_Threads; i++)
{
my_vector_Thread.push_back(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&My_func_for_Thread, My_handle_IOCP, 0, 0));
}


//---------------------------------------------------------------------------------------------------------------------------------------------------



//-------------------------------------------------------------------Initialization Winsock-----------------------------------------------------------

WORD my_version_Winsock = MAKEWORD(2, 2); 

WSADATA my_wsadata_struct; 

int my_WSAStartup = WSAStartup(my_version_Winsock, &my_wsadata_struct);

//------------------------------------------------------------------------------------------------------------------------------------------------------



//-------------------------------------------------------------------Create WSASocket-----------------------------------------------------------------

SOCKET my_WSASocketA = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);

//--------------------------------------------------------------------------------------------------------------------------------------------------------



//-------------------------------------------------------------------

std::string myString_IP = "XX.XXX.XX.XXX";

//--------------------------------------------------------------------------

sockaddr my_sockaddr;                 

my_sockaddr = { 0 };                                            
my_sockaddr.sa_family = 2;                                          // AF_INET.
inet_pton(AF_INET, myString_IP.c_str(), &my_sockaddr.sa_data[2]);   
my_sockaddr.sa_data[1] = 80;                                     //http port

//--------------------------------------------------------------------------


int status_WSAConnect = WSAConnect(my_WSASocketA, &my_sockaddr, sizeof(my_sockaddr), NULL, NULL, NULL, NULL);


//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------




//-------------------------------------------------------------------Bind socket and port--------------------------------------------------------

My_handle_Create_IOCP = CreateIoCompletionPort((HANDLE)my_WSASocketA, My_handle_IOCP, NULL, 0);

//-------------------------------------------------------------------------------------------------------------------------------------------------




//-------------------------------------------------------------------Send message to serever with WSASend-----------------------------------

WSABUF my_WSABUF;

std::string request_text_string = "GET / HTTP/1.1rnHost: government.rurnConnection: keep-alivernrn";


my_WSABUF.buf = &request_text_string[0];
my_WSABUF.len = request_text_string.size();


WSAOVERLAPPED my_WSAOVERLAPPED;
my_WSAOVERLAPPED = { 0 };



int my_WSASend =  WSASend(my_WSASocketA, &my_WSABUF, 1, NULL, 0, &my_WSAOVERLAPPED, NULL);


if (my_WSASend == SOCKET_ERROR)
{
std::cout << "WSASend == SOCKET_ERROR:" std::endl;
}

if (my_WSASend == 0)
{
std::cout << "WSASend == 0: no error" std::endl;
}


//-----------------------------------------------------------------------------------------------------------------------------------------------------------



Sleep(10000);


//---------------------------------------------------------
for (int i = 0; i < Number_Threads; i++)
{
CloseHandle(my_vector_Thread[i]);
}
//---------------------------------------------------------

}

但是,GetQueuedCompleteStatus总是返回998-对内存位置的访问无效。哪个内存被禁止访问?我做错了什么?

您的代码有几个问题。

您的My_func_for_Thread()函数具有与CreateThread()一起使用的错误签名。编译器并没有抱怨,因为您正在使用类型转换来阻止编译器失败。

您正在向GetQueuedCompletionStatus()lpCompletionKey参数传递一个未初始化的指针。它需要一个指向有效ULONG_PTR变量的指针,以便写入。

WSAOVERLAPPED需要在内存中保持活动状态,直到从IOCP队列中检索到其最终状态。但是线程的睡眠时间比main()的运行时间长得多。您应该动态分配WSAOVERLAPPED,然后在收到其状态时释放它。

试试类似的东西:

DWORD WINAPI My_func_for_Thread(LPVOID lpParameter)
{
HANDLE iocp = (HANDLE) lpParameter;
DWORD my_DWORD;
ULONG_PTR  my_CompletionKey;
WSAOVERLAPPED* my_WSAOVERLAPPED_1;
DWORD my_GetLastError;
while (TRUE)
{
BOOL my_BOOL_GetQueuedCompletionStatus = GetQueuedCompletionStatus(iocp, &my_DWORD, &my_CompletionKey, (LPOVERLAPPED*) &my_WSAOVERLAPPED_1, INFINITE);
my_GetLastError = GetLastError();
if (my_BOOL_GetQueuedCompletionStatus)
{
delete my_WSAOVERLAPPED_1;
}
else
{
std::cout << "GetQueuedCompletionStatus == FALSE" << std::endl;
}
}
return 0;
}
int main()
{
...
for (int i = 0; i < Number_Threads; i++)
{
HANDLE hThread = CreateThread(NULL, 0, &My_func_for_Thread, My_handle_IOCP, 0, NULL);
if (hThread)
my_vector_Thread.push_back(hThread);
}
...
std::string request_text_string = "GET / HTTP/1.1rnHost: government.rurnConnection: keep-alivernrn";
WSABUF my_WSABUF;
my_WSABUF.buf = &request_text_string[0];
my_WSABUF.len = request_text_string.size();
WSAOVERLAPPED *my_WSAOVERLAPPED = new WSAOVERLAPPED;
*my_WSAOVERLAPPED = { 0 };
int my_WSASend =  WSASend(my_WSASocketA, &my_WSABUF, 1, NULL, 0, my_WSAOVERLAPPED, NULL);
// wait for request to finish...
// wait for response to arrive...
// close socket...
// wait for threads to terminate...
...
for (size_t i = 0; i < my_vector_Thread.size(); i++)
{
CloseHandle(my_vector_Thread[i]);
}
return 0;
}