C++ Winsock套接字错误:10038(WSAENOTSOCK)

4
我有一个主从应用程序,主机在WinXp(i7,2.1 GHz)上运行,从机是控制器板。主机向从机发送请求,从机以周期性方式向主机发送数据。从机每0.5毫秒循环发送的数据为1000字节。 当主机发出发送数据的请求时,控制台会报告错误。
“Select()函数错误代码:10038”。
这是WSAENOTSOCK的代码。
该应用程序是一个单线程应用程序,从从机接收数据。 从错误信息来看,似乎在select函数检查套接字之前已经关闭了套接字。
请问有谁能指点我方向吗?
:::源代码::::
int Receive()
{
    int rc;
    socklen_t cli_alen;
    struct timeval to;
    fd_set read_fd, write_fd, excep_fd;

    FD_ZERO(&write_fd);
    FD_ZERO(&excep_fd);

sock_again:
    if (!_isSocketOpen) 
    {
        return 0;
    }
    FD_ZERO(&read_fd);
    FD_SET(_sock_fd, &read_fd);
    to.tv_sec =  0;
    to.tv_usec = 0;
    cli_alen = sizeof(SOCKADDR_IN);

    rc = select(_sock_fd+1, &read_fd, &write_fd, &excep_fd, &to);

    if (rc == 0 )  
    {   // Timeout
        // printf("XCP Port %d : select() timded out \n", _port);
        acess = 1;
        goto sock_again;
    } 
    else if (rc == SOCKET_ERROR) 
    {
        // Error
        LogError("XCP: select() error %d", WSAGetLastError());
        closesocket(_sock_fd);
        return -1;
    }
    else 
    {
        // Data
        if (!FD_ISSET(_sock_fd, &read_fd)) 
        {
            LogError("XCP: select() wrong socket descr");
            return -1;
        }
        else
        {
            //read data
            rc = recvfrom(_sock_fd, (char *)_recvBuf, UDP_RECVBUFLEN, 0, (LPSOCKADDR)&_saddr, &cli_alen);
}
}
}

:::: Edited ::::

int CloseUdpConnection()
{
    if (closesocket(_sock_fd) == SOCKET_ERROR) {
        LogError("closesocket() error: %d", WSAGetLastError());
        return -1;
    }
    _isSocketOpen = 0;
    LogError("successfully closed socket %s:%d", _address, _port);
    return 0;
}

::::: 调试跟踪 :::::

xcpApplication.exe -i 192.168.1.100 -p 5555
c
--> Connecting...
<-- Connection established
t
--> Setting daq signal list...
Sorting daq signal list...
Sorting done
<-- Daq signal list set
d
--> Configuring daq lists...
<-- Configuration done
r
--> Starting measurement...
<-- Measurement started

**_sock_fd: -448997078**
XCP: select() error 10038

:::::跟踪信息::::

--> Starting measurement...
<-- Measurement started
_sock_fd: -1963260928 
_sock_fd: 0x8afb0400
XCP: select() error 10038

:::::: Trace ::::

xcpApplication.exe -i 192.168.1.100 -p 5555

_sock_fd: 1936 _sock_fd: 0x790
successfully opened socket 192.168.1.100:5555

--> Connecting...
<-- Connection established
t
--> Setting daq signal list...
Sorting daq signal list...
Sorting done
<-- Daq signal list set
d
--> Configuring daq lists...
<-- Configuration done
c
--> Connecting...
<-- Connection established
r
--> Starting measurement...
<-- Measurement started
_sock_fd: 901186560 _sock_fd: 0x35b70400
XCP: select() error 10038

由于您没有使用write_fdexcept_fd,因此可以将NULL直接传递给select() - Ben Voigt
此外,您正在设置超时时间为0,这意味着您只是检查是否已经有任何数据可用。您可以通过在套接字上设置非阻塞模式并调用recvfrom来获得相同的行为。 - Ben Voigt
数据接收和传递的频率需要足够快,因此我正在使用即时超时,否则由于缓冲区溢出而丢失数据包。 - Pipa's
这不是超时的作用。 - Ben Voigt
@ Ben,感谢你的指导。 如果我错了,请纠正我,这样可能更合适,但不会出现非套接字的套接字操作错误。 看起来套接字已关闭,并且select函数尝试检查read_fd集合中的套接字。 - Pipa's
显示剩余5条评论
1个回答

6
>net helpmsg 10038

An operation was attempted on something that is not a socket.

您可以使用shutdown()函数以TCP/IP协议方式安全地关闭套接字,但不要在使用select()poll()SOCKET句柄上调用closesocket()

实际上,在Win32中,通常更喜欢使用WSAAsyncSelectWSAEventSelect

如果您的应用程序是单线程且不使用异步回调,则无法在select调用期间调用closesocket。我发现您在调用closesocket后立即返回。因此,您必须使用无效套接字进入函数,但_isSocketOpen为真。也许您应该在调用closesocket()时将该标志设置为false。


谢谢,我之前不知道有这个方便的 net helpmsg [errcode] 命令! - Steve Valliere
@Pipa's:你能在调试跟踪中添加socket()返回的值吗?以十六进制打印句柄可能更好看。 - Ben Voigt
1
@Pipa's: 但是看这里——套接字描述符是0x790,但当错误发生时,_sock_fd被填充了垃圾值。套接字没有关闭,但您没有向select传递真正的套接字。我猜您附近有一个缓冲区溢出,正在覆盖您的套接字句柄。 - Ben Voigt
@ Ben, 非常感谢您的帮助!!! 我找到了问题,它出现在从节点上而不是主节点上,这个源代码是为主节点编写的。我尝试了所有可能的调试方法,但仍然无法找到问题。然后使用模拟从节点测试了相同的代码,在这个模拟测试中没有报告任何故障。看来物理从节点存在一些问题,导致了失败。 - Pipa's
1
@Pipa:你肯定有一个错误,导致_sock_fd被破坏。虽然你可以设计你的从机,使其不会遇到这个错误,但你的服务器将留下一个安全漏洞。 - Ben Voigt
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接