Reputation: 11
I've written server and client modules in C++ on Linux Ubuntu 22.04 that allow multiple clients to send messages simultaneously to the server. If one of the clients writes "Hello": server responds with "world!", if one types "disconnect": the connection is broken and if client writes something else, server returns said message to the client.
I have following problem: I set with listen function in server.hpp to operate on maximum two simultaneous connections, but when I compile the program and run it I can launch more than two different clients and server doesn't complain. Why?
This is the code:
main.cpp:
#include "server.hpp"
#include "client.hpp"
int main(int argc, char** argv)
{
try
{
if (argc < 2)
{
std::cout << "Specify the mode: server OR client" << std::endl;
exit(EXIT_FAILURE);
}
if (strcmp(argv[1], "server") == 0)
{
server();
}
if (strcmp(argv[1], "client") == 0)
{
client();
}
}
catch(const std::exception &ex)
{
std::cerr << "Error occured: " << ex.what();
}
catch(...)
{
std::cerr << "Undefined error occured";
}
return 0;
}
server.hpp:
#pragma once
#include <sys/wait.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
void server()
{
const int BUFFER_SIZE = 1024;
const int PORT = 8888;
std::cout << "Launched server\n";
pid_t childPid;
int socket_fd;
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
std::cout << "Unable to create a socket!\n";
exit(EXIT_FAILURE);
}
const int enable = 1;
if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int))<0)
{
std::cout << "setsockopt(SO_REUSEADDR) failed!\n";
}
if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int))<0)
{
std::cout << "setsockopt(SO_REUSEPORT) failed!\n";
}
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = INADDR_ANY;
if (bind(socket_fd, (sockaddr*)&serverAddress, sizeof(serverAddress)) < 0)
{
std::cout << "Unable to bind a socket!\n";
exit(EXIT_FAILURE);
}
if (listen(socket_fd, 2) < 0)
{
std::cout << "Unable to listen\n";
exit(EXIT_FAILURE);
}
struct sockaddr_in cliAddress;
int cliAddress_size = sizeof(cliAddress);
int client_fd;
int cnt = 0;
while(1)
{
std::cout << "Waiting for clients to connect...\n";
std::cout.flush();
if ((client_fd = accept(socket_fd, (sockaddr*)&cliAddress, (socklen_t*)&cliAddress_size)) == -1)
{
std::cout << "Unable to accept!\n";
exit(EXIT_FAILURE);
}
std::cout << "Connection accepted from: " << inet_ntoa(cliAddress.sin_addr) << ":" << ntohs(cliAddress.sin_port) << '\n';
std::cout << "Number of connected clients: " << ++cnt << "\n";
if ((childPid = fork()) == 0)
{
close(socket_fd);
while(1)
{
char buffer[BUFFER_SIZE] = {0};
int bytes_received = read(client_fd, buffer, BUFFER_SIZE);
std::cout << "Received " << bytes_received << " bytes from the client wtih port " << ntohs(cliAddress.sin_port) << " " << buffer << "\n";
if (strcmp(buffer, "Hello") == 0)
{
auto msg = "World!";
std::cout << "Sending a response message...\n";
send(client_fd, msg, strlen(msg), 0);
}
else if (strcmp(buffer, "disconnect") == 0)
{
auto msg = "Disconnecting client\n";
send(client_fd, msg, strlen(msg), 0);
break;
}
else
{
std::cout << "Sending a response message...\n";
send(client_fd, buffer, strlen(buffer), 0);
}
}
close(client_fd);
exit(EXIT_SUCCESS);
}
else
{
close(client_fd);
}
}
}
client.hpp:
#pragma once
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
void client()
{
const int BUFFER_SIZE = 1024;
const int PORT = 8888;
std::cout << "Launched client\n";
int client_fd;
if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
std::cout << "Unable to create a socket!\n";
exit(EXIT_FAILURE);
}
struct sockaddr_in cliAddress;
cliAddress.sin_family = AF_INET;
cliAddress.sin_port = htons(PORT);
cliAddress.sin_addr.s_addr = INADDR_ANY;
if ((connect(client_fd, (sockaddr*)&cliAddress, sizeof(cliAddress))) < 0)
{
std::cout << "Unable to connect!\n";
exit(EXIT_FAILURE);
}
while (1)
{
std::cout << "What message do you want to send to the server? Or do you want to 'disconnect'?\n";
std::string msg_temp;
std::cin >> msg_temp;
const char * msg = msg_temp.c_str();
send(client_fd, msg, strlen(msg), 0);
char buffer[BUFFER_SIZE] = {0};
int bytes_received = read(client_fd, buffer, BUFFER_SIZE);
std::cout << "Received " << bytes_received << " bytes from the server: " << buffer << "\n";
if (strcmp(msg, "disconnect") == 0)
{
break;
}
}
close(client_fd);
}
Makefile:
output: main.o
g++ -std=c++20 main.o -o output
main.o: main.cpp client.hpp server.hpp
g++ -std=c++20 -c main.cpp
clean:
rm *.o output
Upvotes: 1
Views: 82
Reputation: 31459
A listen()
backlog of 2 does not mean that only 2 clients can be connected. It means that a maximum of two clients can be in the (kernel) queue waiting to connect.
If you want to limit the number of simultaneously connected clients, you'll have to write your own code/logic to do that by keeping track of the currently connected clients and when someone disconnect and new ones connect.
Upvotes: 2