Выберите в сокет программирования висит на некоторое время в Windows? - PullRequest
0 голосов
/ 02 ноября 2011

Я новичок в программировании на С ++, и я немного исследовал зависание приложения при отправке данных через программирование сокетов, так как всякий раз, когда происходит изменение между основным и дополнительным серверами при создании и подключении к сокету, я использую код ниже и я видел, что иногда это занимает больше времени или зависает в 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;

Ответы [ 2 ]

2 голосов
/ 02 ноября 2011

Вы знаете, что звонок на select блокируется, верно? Он не даст контроль (возврат), пока не будет чем заняться.

Будь то, читать или писать (подключиться, входит в это)

Так что это не зависание или заморозка, оно просто было разработано так.

Кроме того, почему вы смешиваете сокеты Беркли с сокетами WSA, если вы уже используете Winsock, не смешивайте это с кодом сокетов Беркли, это не имеет особого смысла, используйте функции с префиксом WSA.

0 голосов
/ 03 ноября 2011

Вы проверяете только возвращаемое значение 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 ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...