2016-07-31 38 views
2

为什么socket()没有返回INVALID_SOCKET?我认为它会失败,然后我可以退出我的功能。我的函数的错误检查一直持续到recvfrom(),然后在没有互联网连接时挂起。我以为socket()sendto()会返回一个错误代码,当我没有互联网连接,但他们不是。我试图依靠他们的失败作为一个标志,用户没有互联网连接并退出我的功能,但这只是不工作的一些奇怪的原因。当没有互联网连接时,socket()和sendto()不返回错误代码

void myFunc() 
{ 
    WSADATA wsaData; 
    WSAStartup(MAKEWORD(2, 2), &wsaData); 

    struct sockaddr_in server_addr; 
    memset(&server_addr, 0, sizeof(server_addr)); 
    server_addr.sin_family = AF_INET; 
    server_addr.sin_addr.s_addr = inet_addr("myipaddress"); 
    server_addr.sin_port = htons(123); 

    // Doesn't fail when there's no internet connection 
    protoent *proto = getprotobyname("udp"); 
    int s = socket(PF_INET, SOCK_DGRAM, proto->p_proto); 
    if (s == INVALID_SOCKET) { 
     goto Cleanup; 
    } 

    // Doesn't fail when there's no internet connection 
    char msg[48] = { 0x08, 0, 0, 0, 0, 0, 0, 0, 0 }; 
    int iResult = sendto(s, msg, sizeof(msg), 0, (struct sockaddr *) &server_addr, sizeof(server_addr)); 
    if (iResult == SOCKET_ERROR) { 
     goto Cleanup; 
    } 

    // Hangs when there's no internet connection 
    memset(msg, 0, sizeof(msg)); 
    struct sockaddr saddr; 
    socklen_t saddr_l = sizeof(saddr); 
    iResult = recvfrom(s, msg, 48, 0, &saddr, &saddr_l); 
    if (iResult == SOCKET_ERROR) { 
     goto Cleanup; 
    } 

Cleanup: 
    closesocket(s); 
    WSACleanup(); 
} 
+2

风格问题 - 您可以通过使用RAII技术来清除那些'goto Cleanup;'调用,其中清理将在函数返回时自动发生。 – PaulMcKenzie

+0

@PaulMcKenzie是的,但假设'myFunc()'的用户会一直足够体贴/记住在使用该函数后进行清理。 – Merl

+1

你会如何定义“没有互联网连接”?请注意,您使用的数据报套接字定义不可靠。 –

回答

2

因为没有要求将套接字连接到互联网。许多应用程序在一台机器上使用套接字进行进程间通信。没有互联网连接时,这些应用程序仍可以正常运行。

sendto()可以说可以返回一个错误代码;它可以(在某些情况下,如桌面上有关网络连接状态的通知所示)知道该数据包永远不会被传送。然而,UDP通信和sendto()不保证交付任何,显然你正在使用的实现不考虑缺乏连接值得错误代码。可以说这是一个实施质量问题。

recvfrom()只要您为消息指定(可能无限期地),但从未接收到消息就等待。再次,这是在规范范围内,无论这种特定情况是否被标记,它都可以被认为是实施质量问题。

+0

上使用定时等待机制(select,epoll,...)“它应该知道”究竟如何?你能提出一个机制吗? –

+0

这不是很明显吗?一旦你指定了一个地址,就清楚它是否是本地机器上的地址。如果没有网络连接(可检测到的情况;至少我的机器会立即告诉我是否拉网线),则无法传送。 –

+0

(1)网络电缆!=互联网连接(2)没有网络电缆!=无法送达的数据包(我的头顶上,你可以运行一个虚拟机,只有VM的定制内核模块知道哪些数据包可交付给它)。 –

0

我看着Linux手册页的sendto(假设所有相关的实现是充分类似于Berkeley套接字基线)位置:

http://linux.die.net/man/2/sendto

的文件没有提到如果报告和错误网络堆栈'知道'该消息无法传递。这是合理的,因为套接字的传输可能不是IP4或IP6。它可以是我们选择编写驱动程序的任何传输方式:数据包收音机,串行电缆或运载鸽子(如果我们能够计算将打印的信息加载到其书包中的硬件)。

唯一参照从传输可能的错误是在这里:

这些是由套接字层产生的一些标准误差。可能会生成其他错误并从底层协议模块返回; 参见他们各自的手册页

正如其他人所说的,UDP是一种不可靠的数据报协议。预计不可靠。预计未送达消息。因此不是真的是一个错误。协议层作者编写代码来处理传输错误的动机不大 - 因为它们也是可以预期的,而不是在此协议的上下文中出现错误。

当通过TCP打开套接字时,套接字连续性缺失是一个错误。如果传输报告数据包传输不可能(足够长时间),那么这是协议中的错误条件。

相关问题