When binding a client TCP socket to a specific local port with Winsock, SO_REUSEADDR does not have any effect

前端 未结 3 1450
执笔经年
执笔经年 2020-12-09 00:56

I\'m binding a client TCP socket to a specific local port. To handle the situation where the socket remains in TIME_WAIT state for some time, I use

相关标签:
3条回答
  • 2020-12-09 01:14

    Be careful in binding the local port NOT to use the loopback address "127.0.0.1", or you will get connection timeouts. Better not to populate the sa_loc.sin_addr.s_addr at all - that works just fine.

    0 讨论(0)
  • 2020-12-09 01:18

    When you create a socket with socket(), it has only a type and a protocol family. The ideal is to bind() it to a local address:port too.

    The error you mentioned normally happens when the last connection to the same host:port didn't have a graceful shutdown (FIN/ACK FIN/ACK). In these cases, the socket stays in TIME_WAIT state for a certain period of time (OS dependent, but adjustable).

    What happens then is when you try to connect() to the same host and same port, it uses the default socket's name/address/port/etc, but this combination is already in use by your zombie socket. To avoid this, you can change the local address:port used to establish the connection by calling bind() after the socket creation, providing the sockaddr struct filled with your local address and a random port.

    int main() {
        int ret, fd;
        struct sockaddr_in sa_dst;
        struct sockaddr_in sa_loc;
        char buffer[1024] = "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n";
    
        fd = socket(AF_INET, SOCK_STREAM, 0);
    
        // Local
        memset(&sa_loc, 0, sizeof(struct sockaddr_in));
        sa_loc.sin_family = AF_INET;
        sa_loc.sin_port = htons(LOCAL_RANDOM_PORT);
        sa_loc.sin_addr.s_addr = inet_addr(LOCAL_IP_ADDRESS);
    
        ret = bind(fd, (struct sockaddr *)&sa_loc, sizeof(struct sockaddr));
        assert(ret != -1);
    
        // Remote
        memset(&sa_dst, 0, sizeof(struct sockaddr_in));
        sa_dst.sin_family = AF_INET;
        sa_dst.sin_port = htons(80);
        sa_dst.sin_addr.s_addr = inet_addr("64.233.163.104"); // google :)
    
        ret = connect(fd, (struct sockaddr *)&sa_dst, sizeof(struct sockaddr));
        assert(ret != -1);
    
        send(fd, buffer, strlen(buffer), 0);
        recv(fd, buffer, sizeof(buffer), 0);
        printf("%s\r\n", buffer);
    }
    

    UPDATE: As using a specific local port is a requirement, consider setting SO_LINGER with l_onoff=1 and l_linger=0 so your socket won't block upon close/closesocket, it will just ignore queued data and (hopefully) close the fd. As a last resort you can adjust the TIME_WAIT delay by changing the value of this registry key (highly discouraged!):

    HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay
    
    0 讨论(0)
  • 2020-12-09 01:33

    You don't specify which Windows platform you're running on, that may affect things as may the security principal that you're running under (i.e. are you admin?)...

    This may help: http://blogs.msdn.com/wndp/archive/2005/08/03/Anthony-Jones.aspx

    0 讨论(0)
提交回复
热议问题