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