当互联网关闭时,如何终止windows套接字?(C++WinAPI)



我已经建立了Winsock2连接,但我需要解决互联网中断的情况。这是我的密码;

#include <winsock2.h>
#include <windows.h>
#include <ctime>
int main()
{
WSADATA w;
if(WSAStartup(MAKEWORD(2,2),&w)) return 0;
sockaddr_in sad;
sad.sin_family=AF_INET;
sad.sin_addr.s_addr=inet_addr("200.20.186.76");
sad.sin_port=htons(123);
sockaddr saddr;
int saddr_l=sizeof(saddr);
int s=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(s==INVALID_SOCKET) return 0;
char msg[48]={8};
if(sendto(s,msg,sizeof(msg),0,(sockaddr*)&sad,sizeof(sad))==SOCKET_ERROR) return 0;
if(recvfrom(s,msg,48,0,&saddr,&saddr_l)==SOCKET_ERROR) return 0;
if(closesocket(s)==SOCKET_ERROR) return 0;
if(WSACleanup()) return 0;
return 0;
}

在这里,它等待调用返回,正如它所记录的那样。我有两个问题。

  1. 我可以像使用select时那样设置超时吗
  2. 否则我该如何阻止等待并使其立即返回?文件规定:

发出阻塞Winsock调用(如sendto(时,Winsock可能需要等待网络事件才能完成调用。在这种情况下,Winsock会执行一个可提醒的等待,该等待可能会被同一线程上调度的异步过程调用(APC(中断。

如何做到这一点?

如果你想发出一个recvfrom((并立即返回,然后自己决定等待多长时间(我假设Windows,因为你包含了winsock2.h(,你可以发出一个异步OVERLAPPED请求,然后等待OVERLAPPED结构的hEvent成员发出信号,随时等待完成。

这是一个基于原始代码的更新示例。

  • 您可以通过等待WaitForSingleObject来设置超时(下面我等待了6次10秒(
  • 通过传递OVERLAPPED指针,表示您将自己等待完成。请注意,在发出hEvent信号之前,OVERLAPPED结构不能超出作用域。(如果OVERLAPPED是动态分配的,则释放(
  • 在保证IO完成之前让OVERLAPPED超出范围是一个常见的Winsock错误(我已经在Winsock上工作了大约10年——我见过这个错误的很多变体(
  • 正如下面所评论的,如果您不知道hEvent已经被发出信号,那么在调用closesocket之后,您必须等待hEvent被发出信号才能继续-closesocket不能保证所有异步IO请求在返回之前都已完成
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <windows.h>
#include <ctime>
int main()
{
WSADATA w;
if (WSAStartup(MAKEWORD(2, 2), &w)) return 0;
sockaddr_in sad;
sad.sin_family = AF_INET;
sad.sin_addr.s_addr = inet_addr("200.20.186.76");
sad.sin_port = htons(123);
sockaddr saddr;
int saddr_l = sizeof(saddr);
int s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == INVALID_SOCKET) return 0;
char msg[48] = { 8 };
if (sendto(s, msg, sizeof(msg), 0, (sockaddr*)&sad, sizeof(sad)) == SOCKET_ERROR) return 0;
OVERLAPPED ov{};
ov.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
if (ov.hEvent == nullptr) return 0;
WSABUF wsabuffer{};
wsabuffer.buf = msg;
wsabuffer.len = 48;
DWORD flags = 0;
if (WSARecvFrom(s, &wsabuffer, 1, nullptr, &flags, &saddr, &saddr_l, &ov, nullptr) == SOCKET_ERROR)
{
DWORD gle = WSAGetLastError();
if (gle != WSA_IO_PENDING) return 0;
}
for (DWORD recv_count = 0; recv_count < 6; ++recv_count)
{
DWORD wait = WaitForSingleObject(ov.hEvent, 10000);
if (wait == WAIT_FAILED) return 0;
if (wait == WAIT_OBJECT_0) break; // WSARecvFrom completed
if (wait == WAIT_TIMEOUT) continue; // WSARecvFrom is still pended waiting for data
}
// assuming WSARecvFrom completed - i.e. ov.hEvent was signaled
DWORD transferred;
if (WSAGetOverlappedResult(s, &ov, &transferred, FALSE, &flags))
{
// WSARecvFrom completed successfully - 'transferred' shows the # of bytes that were received
}
else
{
DWORD gle = WSAGetLastError();
gle;
// WSARecvFrom failed with the error code in 'gle'
}
if (closesocket(s) == SOCKET_ERROR) return 0;
// with real code, we must guarantee that hEvent is set after calling closesocket
// e.g. if we get here in an error path
// closesocket() won't guarantee all async IO has completed before returning
WaitForSingleObject(ov.hEvent, INFINITE);
if (WSACleanup()) return 0;
return 0;
}

最新更新