首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >切换回阻塞套接字后无法连接到套接字

切换回阻塞套接字后无法连接到套接字
EN

Stack Overflow用户
提问于 2014-09-28 11:50:26
回答 1查看 852关注 0票数 0

有两个套接字服务器,一个是不总是打开的主服务器,另一个是备份服务器。

我的程序将尝试使用非块连接连接主服务器(以便可以应用超时val ),如果失败,它将使用阻塞连接连接备份服务器。

但是,在大多数情况下,第二个connect函数将返回“无效参数”错误代码:

代码语言:javascript
复制
#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;
    }
}

正如我对上面的代码所评论的,第二个"connect“调用将在大多数时间返回SOCKET_ERROR,而WSAGetLastError()返回WSAEINVAL (无效参数)。

如果我删除非阻塞代码,它将连接没有错误。我的密码怎么了?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-09-28 18:52:32

connect()仍忙于连接时,您必须将套接字保持在非阻塞模式下。只有当select()返回WSAEWOULDBLOCK时才调用WSAEWOULDBLOCK,您还需要检查select()的返回值。您还泄漏了getaddrinfo()返回的内存。

尝试更像这样的东西:

代码语言:javascript
复制
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;
}

然后你就可以这样做:

代码语言:javascript
复制
#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 ...
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26084575

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档