I am trying to understand how the backlog
parameter in int listen(int sockfd, int backlog);
affects how new connections are handled.
Here is my server program.
/* server.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
int main()
{
int sockfd;
int ret;
int yes = 1;
struct addrinfo hints, *ai;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((ret = getaddrinfo(NULL, "8000", &hints, &ai)) == -1) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
return 1;
}
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sockfd == -1) {
perror("server: socket");
return 1;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) == -1) {
perror("server: setsockopt");
close(sockfd);
return 1;
}
if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) == -1) {
perror("server: bind");
close(sockfd);
return 1;
}
freeaddrinfo(ai);
if (listen(sockfd, 2) == -1) {
perror("server: listen");
close(sockfd);
return 1;
}
printf("server: listening ...\n");
printf("server: sleep() to allow multiple clients to connect ...\n");
sleep(10);
printf("server: accepting ...\n");
while (1) {
int connfd;
struct sockaddr_storage client_addr;
socklen_t client_addrlen = sizeof client_addr;
char buffer[1024];
int bytes;
connfd = accept(sockfd, (struct sockaddr *) &client_addr, &client_addrlen);
if (connfd == -1) {
perror("server: accept");
continue;
}
if ((bytes = recv(connfd, buffer, sizeof buffer, 0)) == -1) {
perror("server: recv");
continue;
}
printf("server: recv: %.*s\n", (int) bytes, buffer);
close(connfd);
}
return 0;
}
Here is my client program.
/* client.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
int main(int argc, char **argv)
{
int sockfd;
int ret;
struct addrinfo hints, *ai;
if (argc != 2) {
fprintf(stderr, "usage: %s MSG\n", argv[0]);
return 1;
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if ((ret = getaddrinfo(NULL, "8000", &hints, &ai)) == -1) {
fprintf(stderr, "client: getaddrinfo: %s\n", gai_strerror(ret));
return 1;
}
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sockfd == -1) {
perror("client: socket");
return 1;
}
if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) == -1) {
perror("client: connect");
close(sockfd);
return -1;
}
printf("client: connected\n");
if (send(sockfd, argv[1], strlen(argv[1]), 0) == -1) {
perror("client: send");
close(sockfd);
return -1;
}
printf("client: send: %s\n", argv[1]);
freeaddrinfo(ai);
close(sockfd);
return 0;
}
I compile and run these programs with the following script.
# run.sh
gcc -std=c99 -Wall -Wextra -Wpedantic -D_DEFAULT_SOURCE server.c -o server
gcc -std=c99 -Wall -Wextra -Wpedantic -D_DEFAULT_SOURCE client.c -o client
./server &
sleep 1
./client hello1 &
sleep 1
./client hello2 &
sleep 1
./client hello3 &
sleep 1
./client hello4 &
sleep 1
./client hello5 &
sleep 5
pkill server
When I run the above script, I get this output.
$ sh run.sh
server: listening ...
server: sleep() to allow multiple clients to connect ...
client: connected
client: send: hello1
client: connected
client: send: hello2
client: connected
client: send: hello3
client: connected
client: send: hello4
client: connected
client: send: hello5
server: accepting ...
server: recv: hello1
server: recv: hello2
server: recv: hello3
The output shows that while the server was sleeping between listen()
and accept()
, all five clients could successfully connect()
and send()
to the server. However, the server could accept()
and recv()
three clients only.
I don't understand the following.
listen()
with the backlog
parameter as 2
. Why did all five clients succeed in connect()
-ing then? I was expecting only 2 connect()
s to be successful.accept()
and recv()
from 3 clients instead of 2?The server program invokes listen() with the backlog parameter as 2. Why did all five clients succeed in connect()-ing then?
backlog
parameter is only a hint for listen()
. From POSIX doc:
The backlog argument provides a hint to the implementation which the implementation shall use to limit the number of outstanding connections in the socket's listen queue. Implementations may impose a limit on backlog and silently reduce the specified value. Normally, a larger backlog argument value shall result in a larger or equal length of the listen queue. Implementations shall support values of backlog up to SOMAXCONN, defined in .
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