客户端套接字是可绑定的,但不可连接,因为已经在使用中

时间:2019-06-17 17:44:33

标签: c++ tcp winsock

我写了一个客户端,必须绑定客户端套接字。这很好。之后,我尝试连接Socket,并收到错误10048。(地址已在使用中。)我不知道怎么可能。

我必须实现与多个服务器对话的客户端。每个服务器仅接受来自特定端口的消息。 (每个服务器都期望使用不同的端口)。所以我必须绑定我的客户端套接字。上面的代码将创建这些套接字之一。 我的代码有时会起作用。但是通常连接会给我错误10048,而之前的绑定很好。我知道如果套接字已经在使用中,bind也会给出错误10048。但事实并非如此。它返回0。所以我想端口是空闲的。绑定后,我立即调用connect并收到错误10048。我不明白为什么?在绑定时,端口显然是空闲的。

bool TEthernetSocket::Open()
{
    WSADATA wsaData;

    if (WSAStartup((MAKEWORD(2, 0)), &wsaData) == SOCKET_ERROR)
    {
       return IsConnected();
    }

    Socket = socket(AF_INET, SOCK_STREAM, 0); // TCP

    if (Socket == INVALID_SOCKET)
    {
        return false;
    }

    //bind Socket
    struct sockaddr_in sa_loc;
    memset(&sa_loc, 0, sizeof(struct sockaddr_in));
    sa_loc.sin_family = AF_INET;
    sa_loc.sin_port = htons(ClientPort);
    sa_loc.sin_addr.s_addr = inet_addr(IPClient.substr(0, 15).c_str());

    CALL_TRACE_CB("ethernetSocket connected");

    if (!(bind(Socket, (struct sockaddr*)&sa_loc, sizeof(struct  
    sockaddr))))
    {
        CALL_TRACE_CB("Bind works");
    }
    else
    {
        AnsiString msg = AnsiString().sprintf("EN: error socket Bind: 
        %d", WSAGetLastError());
        CALL_ERROR_CB(ERROR_NO_PORT_HANDLE, msg.c_str());
        Close();
    }


    // TCP
    SOCKADDR_IN sAdd;
    sAdd.sin_family = AF_INET;
    sAdd.sin_port = htons(Port);
    sAdd.sin_addr.s_addr = inet_addr(IP.substr(0, 15).c_str());

    if (connect(Socket, (SOCKADDR*)&sAdd, sizeof(SOCKADDR_IN)) ==    
    SOCKET_ERROR)
    {
        AnsiString msg = AnsiString().sprintf("EN: error connect        
        errorcode: %d", WSAGetLastError());
    }
}

我希望bind()在连接返回此错误之前返回10048,但实际上只有connect()返回此错误

1 个答案:

答案 0 :(得分:1)

  

我必须实现与多个服务器对话的客户端。服务器仅接受来自特定端口的消息,因此我必须绑定我的客户端套接字。

这是一个无法解决的问题。进行出站TCP连接时,本地IP地址和端口的组合专门为该特定的出站TCP连接保留。如果需要从同一端口建立多个出站TCP连接,则每个都必须绑定到其自己的本地IP地址。这将非常不便。

还有其他问题。假设您完成一个连接,然后尝试启动一个新的连接。新的将具有相同的本地IP地址,本地端口(因为服务器只能容忍一个),远程IP地址和远程端口。新连接的数据包如何与旧的旧数据包区分开?

这就是为什么在尝试connect时收到错误消息的原因。直到知道连接的所有四个参数(本地和远程地址以及本地和远程端口)后,才能检测到与先前连接的冲突。直到您致电connect为止,这一点是未知的。

您需要修复服务器以忽略源端口。如果绝对不能做到这一点,则必须采用等待重试机制来处理与过去连接的冲突。