在 Windows 中,套接字编程中的选择会挂起一段时间?

发布于 2024-12-13 14:33:14 字数 4087 浏览 0 评论 0原文

我是 C++ 编程新手,我在通过套接字编程发送数据时调查了一些应用程序挂起的情况,因为每当创建和连接到套接字时主服务器和辅助服务器之间发生转换时,我都会使用下面的代码,并且我有有时会发现它需要更多时间或冻结在 SELECT 位置。代码如下。我能否知道当我使用静态类并使用不同类中的静态类发送数据时,是否会存在线程安全问题,即是否会丢失数据?下面的所有代码都是创建并连接到套接字所必需的吗?

 USES_CONVERSION;
SOCKADDR_IN ServerAddr; 

// Initialize ServerAddr
memset(&ServerAddr,0,sizeof(ServerAddr));
ServerAddr.sin_family       = AF_INET;
ServerAddr.sin_addr.s_addr  = inet_addr(ipAddress); 
ServerAddr.sin_port         = htons((u_short)portNo);









// Create SocketPrimary
SocketPrimary = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);





if (SocketPrimary == INVALID_SOCKET) 
{
    LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - WSASocket(TCP) call with error %ld"), WSAGetLastError());
    return false;
}






// Set timeout option
if (setsockopt(SocketPrimary, SOL_SOCKET, SO_RCVTIMEO, (char *)&RecieveTimeOut, sizeof(RecieveTimeOut)) == SOCKET_ERROR)
{
    LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - a setsockopt for SO_RCVTIMEO call with error %ld"), WSAGetLastError());
    Close(SocketPrimary,TRUE);
    return false;
}






// Set timeout option
if (setsockopt(SocketPrimary, SOL_SOCKET, SO_SNDTIMEO, (char *)&SendTimeOut, sizeof(SendTimeOut)) == SOCKET_ERROR)
{
    LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - a setsockopt for SO_SNDTIMEO call with error %ld"), WSAGetLastError());
    Close(SocketPrimary,TRUE);
    return false;
}





// Set connect portno on address
if (WSAHtons(SocketPrimary, (u_short)portNo, &(ServerAddr.sin_port)) == SOCKET_ERROR) 
{
    LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - a WSAHtons call with error %ld"), WSAGetLastError());
    Close(SocketPrimary,TRUE);
    return false;
}






// Set non-blocking
DWORD BlockMode = 1;
if (ioctlsocket(SocketPrimary, FIONBIO, &BlockMode) == SOCKET_ERROR)
{
    LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed -  a ioctlsocket (non-blocking) call with error %ld"), WSAGetLastError());
    Close(SocketPrimary,TRUE);
    return false;
}





// Connect socket
if  (WSAConnect(SocketPrimary, (struct sockaddr *)&ServerAddr, sizeof(ServerAddr), NULL, NULL, NULL, NULL) == SOCKET_ERROR) 
{
    int ConnectError = WSAGetLastError();
    if (ConnectError != WSAEWOULDBLOCK)
    {
        LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T("Primary server connection failed -  to connect to server with error %ld"),  ConnectError);
        Close(SocketPrimary,TRUE);
        return false;
    }
}

// Wait for connect (use select as the socket is non-blocking at this time)
fd_set ConnectSockets;
ConnectSockets.fd_count = 1;
ConnectSockets.fd_array[0] = SocketPrimary;

TIMEVAL Timeout;
Timeout.tv_sec = ConnectTimeOut / 1000;
Timeout.tv_usec = (ConnectTimeOut % 1000) * 1000;






if (select(0, NULL, &ConnectSockets, NULL, &Timeout) == SOCKET_ERROR)
{
    LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - a select call with error %ld"),  WSAGetLastError());
    Close(SocketPrimary, TRUE);
    return false;
}
else
{
    if (ConnectSockets.fd_count == 0)
    {
        LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed -  timedout to connect..."));
        Close(SocketPrimary, TRUE);
        return false;
    }
}





// Set blocking
BlockMode = 0;
if (ioctlsocket(SocketPrimary, FIONBIO, &BlockMode) == SOCKET_ERROR)
{
    LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - a ioctlsocket (blocking) call with error %ld"), WSAGetLastError());
    Close(SocketPrimary, TRUE);
    return false;
}

LogToEventLog(EVENTLOG_INFORMATION_TYPE, 0, _T(" connected to primary server with local socket id %ld"), SocketPrimary);



// Return
return true;

A i am new to c++ programming and I have investigated a bit for hang of application while sending data thru socket programming as whenever there is a shift between primary and secondary servers while creating and connecting to a socket i am using the code below and i have seen it sometimes it is taking more time or freezing at SELECT location. Code is as below. And can i know when i use static class and use this from different classes to send data, will there be problem of thread safety.i.e any loss of data?. Is all the code below is necessary to just to create and connect to a socket?

 USES_CONVERSION;
SOCKADDR_IN ServerAddr; 

// Initialize ServerAddr
memset(&ServerAddr,0,sizeof(ServerAddr));
ServerAddr.sin_family       = AF_INET;
ServerAddr.sin_addr.s_addr  = inet_addr(ipAddress); 
ServerAddr.sin_port         = htons((u_short)portNo);









// Create SocketPrimary
SocketPrimary = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);





if (SocketPrimary == INVALID_SOCKET) 
{
    LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - WSASocket(TCP) call with error %ld"), WSAGetLastError());
    return false;
}






// Set timeout option
if (setsockopt(SocketPrimary, SOL_SOCKET, SO_RCVTIMEO, (char *)&RecieveTimeOut, sizeof(RecieveTimeOut)) == SOCKET_ERROR)
{
    LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - a setsockopt for SO_RCVTIMEO call with error %ld"), WSAGetLastError());
    Close(SocketPrimary,TRUE);
    return false;
}






// Set timeout option
if (setsockopt(SocketPrimary, SOL_SOCKET, SO_SNDTIMEO, (char *)&SendTimeOut, sizeof(SendTimeOut)) == SOCKET_ERROR)
{
    LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - a setsockopt for SO_SNDTIMEO call with error %ld"), WSAGetLastError());
    Close(SocketPrimary,TRUE);
    return false;
}





// Set connect portno on address
if (WSAHtons(SocketPrimary, (u_short)portNo, &(ServerAddr.sin_port)) == SOCKET_ERROR) 
{
    LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - a WSAHtons call with error %ld"), WSAGetLastError());
    Close(SocketPrimary,TRUE);
    return false;
}






// Set non-blocking
DWORD BlockMode = 1;
if (ioctlsocket(SocketPrimary, FIONBIO, &BlockMode) == SOCKET_ERROR)
{
    LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed -  a ioctlsocket (non-blocking) call with error %ld"), WSAGetLastError());
    Close(SocketPrimary,TRUE);
    return false;
}





// Connect socket
if  (WSAConnect(SocketPrimary, (struct sockaddr *)&ServerAddr, sizeof(ServerAddr), NULL, NULL, NULL, NULL) == SOCKET_ERROR) 
{
    int ConnectError = WSAGetLastError();
    if (ConnectError != WSAEWOULDBLOCK)
    {
        LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T("Primary server connection failed -  to connect to server with error %ld"),  ConnectError);
        Close(SocketPrimary,TRUE);
        return false;
    }
}

// Wait for connect (use select as the socket is non-blocking at this time)
fd_set ConnectSockets;
ConnectSockets.fd_count = 1;
ConnectSockets.fd_array[0] = SocketPrimary;

TIMEVAL Timeout;
Timeout.tv_sec = ConnectTimeOut / 1000;
Timeout.tv_usec = (ConnectTimeOut % 1000) * 1000;






if (select(0, NULL, &ConnectSockets, NULL, &Timeout) == SOCKET_ERROR)
{
    LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - a select call with error %ld"),  WSAGetLastError());
    Close(SocketPrimary, TRUE);
    return false;
}
else
{
    if (ConnectSockets.fd_count == 0)
    {
        LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed -  timedout to connect..."));
        Close(SocketPrimary, TRUE);
        return false;
    }
}





// Set blocking
BlockMode = 0;
if (ioctlsocket(SocketPrimary, FIONBIO, &BlockMode) == SOCKET_ERROR)
{
    LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - a ioctlsocket (blocking) call with error %ld"), WSAGetLastError());
    Close(SocketPrimary, TRUE);
    return false;
}

LogToEventLog(EVENTLOG_INFORMATION_TYPE, 0, _T(" connected to primary server with local socket id %ld"), SocketPrimary);



// Return
return true;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

蓝咒 2024-12-20 14:33:14

您确实知道对 select 的调用是阻塞的,对吧?在有事情要做之前,它不会放弃控制(返回)。

无论是读还是写(连接,都包含在其中)

所以这不是挂起或冻结,它只是设计成这样的操作。

另外,为什么要将 Berkeley 套接字与 WSA 套接字混合在一起,如果您已经在使用 Winsock,请不要将其与 Berkeley 套接字代码混合,这并没有多大意义,请使用以 WSA 为前缀的函数.

You do know that the call to select is blocking, right? It won't yield control (return) until there's something to do.

Be it, read or write (connect, is included in that)

So it's not a hang or freeze, it was just designed operate like that.

Also, why are you mixing Berkeley sockets with WSA sockets, if you're already using Winsock don't mix that with the Berkeley sockets code, it doesn't really make a lot of sense, use the functions prefixed with WSA.

秋意浓 2024-12-20 14:33:14

您只是检查 select() 的返回值是否有 SOCKET_ERROR,但是 select() 还可以告诉您是否发生了超时,或者指定的套接字是否设置了) 已发出信号。您忽略了该信息。您也不应该调用 select() 除非 WSAConnect() 报告 WSAEWOULDBLOCK,因为连接可能会立即成功,因此不需要调用select() 根本就没有。

试试这个:

// Connect socket
if  (WSAConnect(SocketPrimary, (struct sockaddr *)&ServerAddr, sizeof(ServerAddr), NULL, NULL, NULL, NULL) == SOCKET_ERROR)
{
    int Result = WSAGetLastError();
    if (Result != WSAEWOULDBLOCK)
    {
        LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T("Primary server connection failed -  to connect to server with error %ld"), Result);
        Close(SocketPrimary, TRUE);
        return false;
    }

    // Wait for connect (use select as the socket is non-blocking at this time)
    fd_set WriteFDS, ErrorFDS;
    FD_ZERO(&WriteFDS);
    FD_ZERO(&ErrorFDS);
    FD_SET(SocketPrimary, &WriteFDS);

    TIMEVAL Timeout;
    Timeout.tv_sec = ConnectTimeOut / 1000;
    Timeout.tv_usec = (ConnectTimeOut % 1000) * 1000;

    Result = select(0, NULL, &WriteFDS, &ErrorFDS, &Timeout);
    if (Result == SOCKET_ERROR)
    {
        LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - a select call with error %ld"), WSAGetLastError());
        Close(SocketPrimary, TRUE);
        return false;
    }

    if (Result == 0)
    {
        LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed -  timeout to connect..."));
        Close(SocketPrimary, TRUE);
        return false;
    }

    if (FD_ISSET(SocketPrimary, &ErrorFDS))
    {
        DWORD SocketError;
        getsockopt(SocketPrimary, SOL_SOCKET, SO_ERROR, (char*)&SocketError, sizeof(SocketError));

        LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - to connect to server with error %u"), SocketError);
        Close(SocketPrimary, TRUE);
        return false;
    }
}

// connected ...

You are only checking the return value of select() for SOCKET_ERROR, but select() can also tell you if the timeout period occured, or if the specified socket set(s) are signaled. You are ignoring that information. You should also not be calling select() unless WSAConnect() reports WSAEWOULDBLOCK, as the connection could succeed immediately adn thus not need a call to select() at all.

Try this:

// Connect socket
if  (WSAConnect(SocketPrimary, (struct sockaddr *)&ServerAddr, sizeof(ServerAddr), NULL, NULL, NULL, NULL) == SOCKET_ERROR)
{
    int Result = WSAGetLastError();
    if (Result != WSAEWOULDBLOCK)
    {
        LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T("Primary server connection failed -  to connect to server with error %ld"), Result);
        Close(SocketPrimary, TRUE);
        return false;
    }

    // Wait for connect (use select as the socket is non-blocking at this time)
    fd_set WriteFDS, ErrorFDS;
    FD_ZERO(&WriteFDS);
    FD_ZERO(&ErrorFDS);
    FD_SET(SocketPrimary, &WriteFDS);

    TIMEVAL Timeout;
    Timeout.tv_sec = ConnectTimeOut / 1000;
    Timeout.tv_usec = (ConnectTimeOut % 1000) * 1000;

    Result = select(0, NULL, &WriteFDS, &ErrorFDS, &Timeout);
    if (Result == SOCKET_ERROR)
    {
        LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - a select call with error %ld"), WSAGetLastError());
        Close(SocketPrimary, TRUE);
        return false;
    }

    if (Result == 0)
    {
        LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed -  timeout to connect..."));
        Close(SocketPrimary, TRUE);
        return false;
    }

    if (FD_ISSET(SocketPrimary, &ErrorFDS))
    {
        DWORD SocketError;
        getsockopt(SocketPrimary, SOL_SOCKET, SO_ERROR, (char*)&SocketError, sizeof(SocketError));

        LogToEventLog(EVENTLOG_WARNING_TYPE, EVENTID_WINSOCK_ERROR, _T(" Primary server connection failed - to connect to server with error %u"), SocketError);
        Close(SocketPrimary, TRUE);
        return false;
    }
}

// connected ...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文