Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the program wait for incoming connections once it goes past listen()

Tags:

c

sockets

I am learning socket programming in c and trying to understand what exactly is listen() doing in the code. I understand it defines the maximum number of connection that can be queued for accept() but other than that I can't seem to understand what else is it doing.

According to the text I'm learning from,

listen() waits for incoming connections. Accept() gets the pending connection on the port you are listen()ing.

Looking at the flow of execution, I see that listen() is, in fact, called only once and after that only accept() is handling whatever new connection that comes in. Then, how does the server listen the future requests if listen() is never called once we get inside the accept loop.?

                       +----------+
                       |socket()  |
                       +----------+

                       +----------+
                       |bind()    |
                       +----------+

                       +----------+
                       |listen()  |
                       +----------+
                       +----------+
                       |while(1)  |
                       |----------|
                       |accept()  |
                       |          |
                       |          |
                       +----------+

Here's the code I am working on:

/*Server*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>

int main()
{
    int sockfd, newsock;
    char buffer[200];
    memset(buffer, 0, sizeof(buffer));

    /*Creating a new socket*/
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("Socket error");
        exit(1);
    }

    /*Creating socket address structure*/
    struct sockaddr_in server_addr, client_address;

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(7200);
    server_addr.sin_addr.s_addr = inet_addr("192.168.1.2");
    bzero(&(server_addr.sin_zero),8);

    /*Binding*/
    if(bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        perror("Bind error");
        exit(1);
    }

    /*Listening for new connection; maximum 5*/
    if(listen(sockfd, 5) < 0)
    {
        perror("Listen error");
    }


    while(1)
    {
        socklen_t len = sizeof(client_address);

        if((newsock = accept(sockfd, (struct sockaddr *)&client_address, &len)) < 0)
        {
            perror("Accept error");
            exit(1);
        }

        int i;
        if((i = read(newsock, buffer, sizeof(buffer))) < 0)
        {
            perror("Receive error");
            exit(1);
        }
        if(i == 0)
        {
            printf("Socket closed remotely\n");
        }
        if(i > 0)
        {
            printf("received %d bytes\n",i);
            printf("data: %s",buffer);
        }

        close(newsock);
    }
    close(sockfd);

    return 0;
}
like image 602
Gaurav Butola Avatar asked Dec 06 '25 18:12

Gaurav Butola


2 Answers

listen() waits for incoming connections.

That's just a misleading simplification. This system call marks the socket for listening. This means it informs the OS hey, look out for this socket, you're going to receive connection requests on it.

The real waiting function is accept. This function waits for incoming connections. Every time you call it (in a blocking context), one of 2 things happen:

  • If there are unaccepted connections (governed by the second listen argument) accept just fetches one and it's done
  • Otherwise it actually waits for connections to become available before returning
like image 173
cnicutar Avatar answered Dec 08 '25 07:12

cnicutar


The listen() function does not wait for connections; it (a) informs the kernel that the socket will be accepting connections and (b) sets the backlog parameter -- how many connections the kernel will queue up before rejecting new connections. listen() is called only once because it just sets things.

The accept() function is what handles new connections. From the man page:

   The accept() function shall extract the first connection on  the  queue
   of  pending  connections, create a new socket with the same socket type
   protocol and address family as the specified socket, and allocate a new
   file descriptor for that socket.

So, listen() sets up the socket, the kernel handles connection establishment, and accept() pulls connections off the queue and makes them available to your code.

like image 20
larsks Avatar answered Dec 08 '25 08:12

larsks