Author Topic: linux, tcp/ip, issues with bind  (Read 3431 times)

0 Members and 1 Guest are viewing this topic.

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
linux, tcp/ip, issues with bind
« on: January 17, 2015, 09:18:57 pm »
Code: [Select]
int tcp_ip_sock_get
(
    int port
)
{
    int                servSock;     /* Socket descriptor for server */
    int                clntSock;     /* Socket descriptor for client */
    struct sockaddr_in echoServAddr; /* Local address */
    struct sockaddr_in echoClntAddr; /* Client address */
    unsigned short     echoServPort; /* Server port */
    unsigned int       clntLen;      /* Length of client address data structure */

    echoServPort = port;

    /* Create socket for incoming connections */
    servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (servSock < 0)
    {
        DieWithError("socket() failed");
        return 0;
    }

    /* Construct local address structure */
    memset(&echoServAddr, 0, sizeof(echoServAddr));     /* Zero out structure */
    echoServAddr.sin_family      = AF_INET;             /* Internet address family */
    echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);   /* Any incoming interface */
    echoServAddr.sin_port        = htons(echoServPort); /* Local port */

//int option=1;
//int reuse=1;
//if(setsockopt(servSock,SOL_SOCKET,(SO_REUSEPORT | SO_REUSEADDR),(char*)&option,sizeof(option)) < 0)
//if(setsockopt(servSock,SOL_SOCKET,(SO_REUSEADDR),(char*)&option,sizeof(option)) < 0)
//    if (setsockopt(servSock, SOL_SOCKET, SO_REUSEPORT,(const char*)&reuse, sizeof(reuse)) < 0)
//{
//        DieWithError("setsockopt failed");
//        return 0;
//}


    /* Bind to the local address */
    if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
    {
        DieWithError("bind() failed");
        return 0;
    }

    /* Mark the socket so it will listen for incoming connections */
    if (listen(servSock, MAXPENDING) < 0)
    {
        DieWithError("listen() failed");
        return 0;
    }

    //while (1)
    //{
        /* Set the size of the in-out parameter */
        clntLen = sizeof(echoClntAddr);

        /* Wait for a client to connect */
        clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr, &clntLen);
        if (clntSock < 0)
        {
            DieWithError("accept() failed");
            return 0;
        }

        /* clntSock is connected to a client! */
        printf("Handling client %s\n", inet_ntoa(echoClntAddr.sin_addr));
        printf(" +sock.server=%ld\n", servSock);
        printf(" +sock.client=%ld\n", clntSock);

    //    HandleTCPClient(clntSock);
    //}
    return clntSock;
}


hi guys
about tcp/ip networking, i am experimenting an issues with bind()

this code is not working, perhaps it works the first time i invoke it, then bind fails, i have to wait 2 seconds, and then it works again

Code: [Select]
while (1)
{
clntSock=tcp_ip_sock_get(2000);
HandleTCPClient(clntSock);
close(clntSock);
}



while the following code is working

Code: [Select]
void tcp_ip_sock
{
    int                servSock;     /* Socket descriptor for server */
    int                clntSock;     /* Socket descriptor for client */
    struct sockaddr_in echoServAddr; /* Local address */
    struct sockaddr_in echoClntAddr; /* Client address */
    unsigned short     echoServPort; /* Server port */
    unsigned int       clntLen;      /* Length of client address data structure */

    echoServPort = 2000;

    /* Create socket for incoming connections */
    servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (servSock < 0)
    {
        DieWithError("socket() failed");
        return 0;
    }

    /* Construct local address structure */
    memset(&echoServAddr, 0, sizeof(echoServAddr));     /* Zero out structure */
    echoServAddr.sin_family      = AF_INET;             /* Internet address family */
    echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);   /* Any incoming interface */
    echoServAddr.sin_port        = htons(echoServPort); /* Local port */

    /* Bind to the local address */
    if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
    {
        DieWithError("bind() failed");
        return 0;
    }

    /* Mark the socket so it will listen for incoming connections */
    if (listen(servSock, MAXPENDING) < 0)
    {
        DieWithError("listen() failed");
        return 0;
    }

    while (1)
    /{
        /* Set the size of the in-out parameter */
        clntLen = sizeof(echoClntAddr);

        /* Wait for a client to connect */
        clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr, &clntLen);
        if (clntSock < 0)
        {
            DieWithError("accept() failed");
            return 0;
        }

        /* clntSock is connected to a client! */
        printf("Handling client %s\n", inet_ntoa(echoClntAddr.sin_addr));
        printf(" +sock.server=%ld\n", servSock);
        printf(" +sock.client=%ld\n", clntSock);

        HandleTCPClient(clntSock);
    }
}




what's wrong with bind()  :-// ?
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: linux, tcp/ip, issues with bind
« Reply #1 on: January 17, 2015, 09:20:37 pm »
my linux hasn't SO_REUSEPORT defined  :-//

 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: linux, tcp/ip, issues with bind
« Reply #2 on: January 17, 2015, 09:24:26 pm »
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: linux, tcp/ip, issues with bind
« Reply #3 on: January 17, 2015, 09:27:57 pm »
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4192
  • Country: us
Re: linux, tcp/ip, issues with bind
« Reply #4 on: January 17, 2015, 09:41:29 pm »
There's a reason that connections sit in TIMEWAIT when they're done.
The usual practice is to pick a different local port on the client side, so that you have:
  client:random --> server:echoport
(I can't tell you how to do that with sockets, though.)
 

Offline legacyTopic starter

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: linux, tcp/ip, issues with bind
« Reply #5 on: January 17, 2015, 10:12:16 pm »
the problem is this:

Quote
Let's say you open a TCP connection. After transmitting data, you close the socket. But in fact, it will be set in TIME_WAIT state (TIME_WAIT == "it's possible that some data have no been delivered yet, or something, so we wait as a cautionous TCP implementation") for a while. You just can't open another connection to the same IP/port, except by using REUSEADDR

i have to think about a solution
 

Offline codeboy2k

  • Super Contributor
  • ***
  • Posts: 1836
  • Country: ca
Re: linux, tcp/ip, issues with bind
« Reply #6 on: January 18, 2015, 12:11:12 am »
Most server implementations would fork (or pre-fork) and hand off the work to another process, which can close the socket after it finishes sending. The main process that is handing the accept() connections is never closed.  So you never get into a TIMEWAIT state.

However, during development and testing you often crash and get into a TIMEWAIT state, that can take between 30s and 120s to expire. So in this case you want to use SO_REUSEADDR on the socket options. And in general your server should use SO_REUSEADDR.

However, SO_REUSEADDR does not let you start a second server on the same port if the port is already in use.  This is why most TCP servers use a worker model, where only one master process opens the socket then it forks after each accepted connection (or pre-forks and hands out work to pre-forked and waiting workers).

Google introduced SO_REUSEPORT to enable them to create a simple server process model that can be executed multiple times on the same host, and each server process can open the same local port.  To do so, they specify SO_REUSEPORT and then the open succeeds.  Incoming connections are handed off fairly to each server listening on the same port, and this is done by the kernel. So this avoids the more complex (and sometimes unfair) user-land pre-forked or multi-threaded but single port server model.

SO_REUSEPORT was introduced in kernel 3.9 (but BSD had it before that).

With your simple server, SO_REUSEPORT would help you out, but you need to use kernel 3.9.

If you can't use kernel 3.9, then your server code needs to fork() after accept(), and in the parent: close the socket (from accept) and continue the loop to go back into accept() for more; (2) in the child, write to the socket (from accept) and close it and exit.

EDIT: in your case, for (2) return the socket descriptor to the caller.  The parent loops back to accept more, and never returns from this function call.
« Last Edit: January 18, 2015, 12:19:10 am by codeboy2k »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf