Reputation: 59
Trying my hand at socket programming in C. When I connect multiple clients to the server and then disconnect them, the server shows that all clients are disconnecting on the same port.
Example: Connecting two clients and then disconnecting them.
./server 59001
Waiting for new connections....
Accepted new connection on 127.0.0.1:37098
Accepted new connection on 127.0.0.1:37100
Host disconnected: 127.0.0.1:37100
Host disconnected: 127.0.0.1:37100
Accepted new connection on 127.0.0.1:37102
Accepted new connection on 127.0.0.1:37106
Host disconnected: 127.0.0.1:37106
Host disconnected: 127.0.0.1:37106
You can see the server shows the two clients disconnecting on the same port. I'm using select for handling multiple clients, here is my server.c file:
#include <stdlib.h>
#include <stdio.h>
#include <string.h> /* memset */
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h> /* inet_addr */
#include <netinet/in.h>
#include <unistd.h> /* close */
#include <sys/select.h> /* select */
#define SIZE 1024
int socket_description(int port, struct sockaddr_in server_addr);
int main(int argc, char const *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Usage: ./server <port>\n\n");
exit(EXIT_FAILURE);
}
int port = atoi(argv[1]);
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
//create TCP socket
int sock_fd = socket_description(port, server_addr);
//set up synchronous i/o for handling multiple clients
fd_set current_sockets, ready_sockets; //create two sets of file descriptors to store, one to track our active connection (current_sock) and the other to hold temporary (ready_sock)
FD_ZERO(¤t_sockets); //initialise current sockets to zero
FD_SET(sock_fd, ¤t_sockets); //adds a file descriptor to the current socket set
//handle client data
char buffer[SIZE];
char *p_buffer = buffer;
int bytes_received;
//accept incoming connections
fprintf(stdout, "Waiting for new connections....\n");
socklen_t sock_len = sizeof(server_addr);
while (1)
{
//copy current set of fds
ready_sockets = current_sockets;
int ready = select(FD_SETSIZE, &ready_sockets, NULL, NULL, NULL);
if (ready < 0)
{
perror("Could not read in ready_socket file descriptors (select error)");
exit(EXIT_FAILURE);
}
//loop over the file descriptors that are ready to be read in
for (int i = 0; i < FD_SETSIZE; i++)
{
if (FD_ISSET(i, &ready_sockets))
{
if (i == sock_fd)
{
// this is a new connection to accept, set the new connection to the client structure
int client = accept(sock_fd,(struct sockaddr *)&client_addr, &sock_len);
if (client < 0)
{
perror("Error accepting incoming connection");
exit(EXIT_FAILURE);
}
char const *client_ip = inet_ntoa(client_addr.sin_addr);
int client_port = ntohs(client_addr.sin_port);
fprintf(stdout, "Accepted new connection on %s:%d\n", client_ip, client_port);
// add the new client to the set
FD_SET(client, ¤t_sockets);
}
else
{
// handle existing connection
if((bytes_received = recv(i,p_buffer,SIZE,0) > 0))
{
//check if the received message ends in a newline character, replace with null byte
if (*(p_buffer + bytes_received) == '\n')
{
*(p_buffer + bytes_received) = '\0';
}
char const *client_ip = inet_ntoa(client_addr.sin_addr);
fprintf(stdout, "Received message from %s: %s", client_ip, p_buffer);
int bytes_sent = send(i, p_buffer, bytes_received, 0);
if (bytes_sent < 0)
{
perror("Error receiving message");
exit(EXIT_FAILURE);
}
}
// host disconnected
else
{
char const *client_ip = inet_ntoa(client_addr.sin_addr);
uint16_t client_port = ntohs(client_addr.sin_port);
fprintf(stdout, "Host disconnected: %s:%d\n", client_ip, client_port);
close(i);
FD_CLR(i, ¤t_sockets);
}
}
}
}
}
return 0;
}
Upvotes: 0
Views: 173
Reputation: 59
Fixed this by updating:
// host disconnected
else
{
char const *client_ip = inet_ntoa(client_addr.sin_addr);
uint16_t client_port = ntohs(client_addr.sin_port);
fprintf(stdout, "Host disconnected: %s:%d\n", client_ip, client_port);
close(i);
FD_CLR(i, ¤t_sockets);
}
to the new version:
// host disconnected
else
{
getpeername(i , (struct sockaddr*)&client_addr, &client_len);
char const *client_ip = inet_ntoa(client_addr.sin_addr);
uint16_t client_port = ntohs(client_addr.sin_port);
fprintf(stdout, "Host disconnected: %s:%d\n", client_ip, client_port);
//close socket and remove client from fd_set
close(i);
FD_CLR(i, ¤t_sockets);
}
Upvotes: 0