2014-09-28 6 views
0

두 개의 소켓 서버가 있습니다. 하나는 항상 켜져 있지 않은 주 서버이고 다른 하나는 백업 서버입니다.블로킹 소켓으로 다시 전환 한 후 소켓에 연결할 수 없습니다.

내 프로그램은 비 블록 연결을 사용하여 기본 서버에 연결하려고 시도하므로 (시간 초과 값을 적용 할 수 있음) 실패한 경우 차단 연결을 사용하여 백업 서버를 연결합니다.

두 번째 연결 기능은 대부분의 시간에 "잘못된 인수"오류 코드가 반환됩니다 그러나 : 나는 위의 코드에 댓글로

#define SERVER_URL "example.com" 
#define SERVER_PORT_PRIMARY "1234" 
#define SERVER_PORT_BACKUP "5678" 

struct addrinfo *result = NULL; 
struct addrinfo hints; 

ZeroMemory(&hints, sizeof(hints)); 
hints.ai_family = AF_INET; 
hints.ai_socktype = SOCK_STREAM; 
hints.ai_protocol = IPPROTO_TCP; 

if (getaddrinfo(SERVER_URL , SERVER_PORT_PRIMARY , &hints, &result) != 0) { 
    WSACleanup(); 
    return; 
} 

SOCKET socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
if (socketClient == SOCKET_ERROR){ 
    WSACleanup(); 
    return; 
} 

//set the socket in non-blocking 
unsigned long iMode = 1; 
iResult = ioctlsocket(socketClient, FIONBIO, &iMode); 
if (iResult != NO_ERROR){ 
    closesocket(socketClient); 
    WSACleanup(); 
    return; 
} 

if (connect(socketClient, result->ai_addr, (int)result->ai_addrlen) == SOCKET_ERROR){ 
    if (WSAGetLastError() != WSAEWOULDBLOCK){ 
     closesocket(socketClient); 
     WSACleanup(); 
     return; 
    } 
} 

//switch it back to blocking socket 
iMode = 0; 
iResult = ioctlsocket(socketClient, FIONBIO, &iMode); 
if (iResult != NO_ERROR){ 
    closesocket(socketClient); 
    WSACleanup(); 
    return; 
} 
fd_set Write, Err; 
FD_ZERO(&Write); 
FD_ZERO(&Err); 
FD_SET(socketClient, &Write); 
FD_SET(socketClient, &Err); 
TIMEVAL Timeout; 
Timeout.tv_sec = 10; 
Timeout.tv_usec = 0; 
select(0, NULL, &Write, &Err, &Timeout); 
if (FD_ISSET(socketClient, &Write) == false){ 
    //unable to connect to primary server within 10s, try to connect backup server 
    ZeroMemory(&hints, sizeof(hints)); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_protocol = IPPROTO_TCP; 
    if (getaddrinfo(SERVER_URL , SERVER_PORT_BACKUP, &hints, &result) != 0) { 
     closesocket(socketClient); 
     WSACleanup(); 
     return; 
    } 
    iResult = connect(socketClient, result->ai_addr, (int)result->ai_addrlen); 
    if (iResult == SOCKET_ERROR){ 
     int a = WSAGetLastError(); ///<----Problem here, a == WSAEINVAL (Invalid argument) 
     closesocket(socketClient); 
     WSACleanup(); 
     return; 
    } 
} 

을, 두 번째 통화는 대부분의 시간과 WSAGetLastError에 SOCKET_ERROR를 반환합니다 "연결"()는 WSAEINVAL (잘못된 인수)을 반환합니다.

비 차단 코드를 제거하면 오류없이 연결됩니다. 그래서 내 코드가 뭐가 잘못 됐어?

답변

0

connect()이 여전히 연결 중일 때 소켓을 비 차단 모드로 두어야합니다. 이 WSAEWOULDBLOCK을 반환하고 select()의 반환 값을 확인해야하는 경우에만 select()으로 전화하십시오. getaddrinfo()에 의해 반환 된 메모리가 유실되었습니다.

대신 이와 비슷한 더 많은 것을보십시오 :

int connectTo(SOCKET s, const char *host, const char *port) 
{ 
    struct addrinfo *result = NULL; 
    struct addrinfo hints; 

    ZeroMemory(&hints, sizeof(hints)); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_protocol = IPPROTO_TCP; 

    int ret = getaddrinfo(host, port, &hints, &result); 
    if (ret != 0) { 
     return ret; 
    } 

    if (connect(socketClient, result->ai_addr, result->ai_addrlen) != SOCKET_ERROR) { 
     freeaddrinfo(result); 
     return 0; 
    } 

    ret = WSAGetLastError(); 
    freeaddrinfo(result); 

    if (ret != WSAEWOULDBLOCK) { 
     return ret; 
    } 

    fd_set Write, Err; 
    FD_ZERO(&Write); 
    FD_ZERO(&Err); 
    FD_SET(s, &Write); 
    FD_SET(s, &Err); 

    TIMEVAL Timeout; 
    Timeout.tv_sec = 10; 
    Timeout.tv_usec = 0; 

    ret = select(0, NULL, &Write, &Err, &Timeout); 
    if (ret == SOCKET_ERROR) { 
     return WSAGetLastError(); 
    } 

    if (ret == 0) { 
     return WSAETIMEDOUT; 
    } 

    if (FD_ISSET(s, &Err)) { 
     u_long err; 
     if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&err, sizeof(err)) == SOCKET_ERROR) { 
      return WSAGetLastError(); 
     } 
     return (int) err; 
    } 

    return 0; 
} 

그럼 당신은이 작업을 수행 할 수 있습니다

#define SERVER_URL "example.com" 
#define SERVER_PORT_PRIMARY "1234" 
#define SERVER_PORT_BACKUP "5678" 

SOCKET socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
if (socketClient == SOCKET_ERROR) { 
    WSACleanup(); 
    return; 
} 

//set the socket in non-blocking 
u_long iMode = 1; 
iResult = ioctlsocket(socketClient, FIONBIO, &iMode); 
if (iResult == SOCKET_ERROR) { 
    closesocket(socketClient); 
    WSACleanup(); 
    return; 
} 

if (connectTo(socketClient, SERVER_URL, SERVER_PORT_PRIMARY) != 0) { 
    if (connectTo(socketClient, SERVER_URL, SERVER_PORT_BACKUP) != 0) { 
     closesocket(socketClient); 
     WSACleanup(); 
     return; 
    } 
} 

//switch it back to blocking socket 
iMode = 0; 
iResult = ioctlsocket(socketClient, FIONBIO, &iMode); 
if (iResult == SOCKET_ERROR) { 
    closesocket(socketClient); 
    WSACleanup(); 
    return; 
} 

// communicate with the server as needed ... 
관련 문제