Sarp Kaya
Sarp Kaya

Reputation: 3784

closing socket in BSD sockets

My code is :

int main(int argc, char *argv[])
{
    int sockfd, new_fd;  /* listen on sock_fd, new connection on new_fd */
    struct sockaddr_in my_addr;    /* my address information */
    struct sockaddr_in their_addr; /* connector's address information */
    socklen_t sin_size;

    /* generate the socket */
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    /* generate the end point */
    my_addr.sin_family = AF_INET;         /* host byte order */
    my_addr.sin_port = htons(MYPORT);     /* short, network byte order */
    my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
        /* bzero(&(my_addr.sin_zero), 8);   ZJL*/     /* zero the rest of the struct */

    /* bind the socket to the end point */
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
    == -1) {
        perror("bind");
        exit(1);
    }

    /* start listnening */
    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    printf("server starts listnening %d...\n",sockfd);

    /* repeat: accept, send, close the connection */
    /* for every accepted connection, use a sepetate process or thread to serve it */
while(1) {  /* main accept() loop */
    sin_size = sizeof(struct sockaddr_in);
    if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
    &sin_size)) == -1) {
        perror("accept");
        continue;
    }
    printf("server: got connection from %s\n", \
        inet_ntoa(their_addr.sin_addr));

    if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
    perror("recv");
    exit(1);
    }

    buf[numbytes] = '\0';

    printf("Received: %s",buf);

    if (send(new_fd, "Hello, world!\n", MAXDATASIZE, 0) == -1)
        perror("send");
        close(new_fd);
        exit(0);

    close(new_fd);  /* parent doesn't need this */

    while(waitpid(-1,NULL,WNOHANG) > 0); /* clean up child processes */
}
return 0;
}

So whenever I execute this server, after one client uses that it terminates. But If I want to execute it again lets say within 60 seconds, then it gives an error of bind: Address already in use I thought the close() function actually releases the socket so that it would be available to use it again instantly. So what am I missing here?

Upvotes: 2

Views: 3023

Answers (4)

funtime
funtime

Reputation: 627

Delay is due to TIME_WAIT

In the process of terminating a connection, the important thing to keep in mind is that the application process on both sides of the connection must independently close its half of the connection. Due to the Three Way Handshake policy of a TCP connection,kernel waits for the acknowledgment that the connection on the other side is also closed

However, You can override this functionality by following methods:

Method 1

In the /etc/sysctl.conf file, add the following lines to persist it after reboot:

net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1

Method 2

echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse

Upvotes: 0

twinj
twinj

Reputation: 2039

Firstly the original form of this code comes from Beej's guide

You have supplied code which is either very wrong or edited for brevity. After sending the "Hello World" response you call exit(0); Please add curly braces.

if (send(new_fd, "Hello, world!\n", MAXDATASIZE, 0) == -1)
    perror("send");
    close(new_fd);
    exit(0);

Beej;s code:

    if (!fork()) { // this is the child process
        close(sockfd); // child doesn't need the listener
        if (send(new_fd, "Hello, world!", 13, 0) == -1)
            perror("send");
        close(new_fd);
        exit(0);
    }
    close(new_fd);  // parent doesn't need this`

May I also point out that Beej's code and yours does not handle the event where 'recv' returns 0 in the case a connection was lost or aborted by the client. On a side note remember a call to recv will block.

if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
perror("recv");
exit(1);
}

While this seems it probably wont affect the crash this particular issue may cause unexpected crashes later when the client is closed unexpectedly.

Upvotes: 0

bobwki
bobwki

Reputation: 944

Also, I don't see where BACKLOG is defined, which you use in the listen() call. If this is by chance set to 1, you may want to increase it. Then, while the last socket closes, you can be handling the next call.

Upvotes: 0

simonc
simonc

Reputation: 42165

Before calling bind, you can mark that you want to potentially reuse an address/port using the SO_REUSEADDR socket option:

int reuseaddr = 1;
int err = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
                     &reuseaddr, sizeof(reuseaddr));

Upvotes: 8

Related Questions