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;
}
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:
accept just fetches one and it's doneThe 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With