Reputation: 169
I am trying to implement a TCP server that can handle multiple connections at a time in C using pthreads
.
Server code
#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<pthread.h>
#include<readline/readline.h>
void* connection_handler(void *arg)
{
int sock_number = *((int *)arg);
printf("New connection with socket No. : %d\n",sock_number);
char *message = "!!!!!!!!!!!!!!!!!! MESSAGE !!!!!!!!!!!!!!!!!!\n";
while(1)
{
write(sock_number,message,strlen(message));
}
}
int main()
{
int sock_desc;
sock_desc = socket(AF_INET,SOCK_STREAM,0);
if(sock_desc<0)
{
perror("Socket error");
}
else
{
printf("Socket created!\n");
struct sockaddr_in server,client;
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(8080);
if(bind(sock_desc,(struct sockaddr*)&server,sizeof(server))<0)
{
perror("Binding error");
}
else
{
printf("Socket bound to 8080 port!\n");
printf("Listening started.........\nWaiting for connections from clients.........\n");
listen(sock_desc,20);
int sock_size = sizeof(struct sockaddr_in);
int new_socket;
pthread_t pid[50];
int connection_count=0;
while((new_socket = accept(sock_desc,(struct sockaddr*)&client,(socklen_t*)&sock_size)))
{
printf("New connection : %s:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
if(pthread_create(&pid[connection_count++],NULL,connection_handler,&new_socket)!=0)
{
perror("Thread error");
}
}
for(int i=0;i<connection_count;i++)
{
pthread_join(pid[i],NULL);
}
}
}
}
The problem is that when one of the client is stopped , the whole server program will be terminated at the same time and also all other clients.But there is no problem with having multiple connections.Anybody please tell why the server is terminating and is there any way to keep the server running even if the client terminates?
Upvotes: 0
Views: 89
Reputation: 21
Let's take a look at this code snippet:
while((new_socket = accept(sock_desc,(struct sockaddr*)&client,(socklen_t*)&sock_size)))
{
printf("New connection : %s:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
if(pthread_create(&pid[connection_count++],NULL,connection_handler,&new_socket)!=0)
{
perror("Thread error");
}
}
for(int i=0;i<connection_count;i++)
{
pthread_join(pid[i],NULL);
}
You have this variable new_socket. You have it's pointer &new_socket. When Client 1 connects, you pass &new_socket to the pthread, Thread 1.
You then get Client 2 connecting. Your variable new_socket, with the same address: &new_socket will then be passed to Thread 2. This effectively means when you accept a new connection, you are overwriting a variable used by your previous socket thread.
This means if a second client connects, before Thread 1 for Client 1
executes int sock_number = *((int *)arg);
They will cause the execution thread to rewrite the value passed to Thread 1, and both clients will be referred to by the same socket
When one client closes the socket, they close the same socket used by every other client.
Your mistake arises from the idea that a new socket object is instantiated by accept, with a new address. This is not the case, as C has no objects. Really your only reference to this socket file descriptor is 'int new_socket` Which is a variable that keeps the same address throughout your while loop.
When you execute new_socket = accept(sock_desc,(struct sockaddr*)&client,(socklen_t*)&sock_size
This simply copies the value of the file descriptor for the socket to new_socket.
A simply way to solve this would be to pass the socket by value:
void* connection_handler(void *arg)
{
int sock_number = ((int)arg)
...
}
...
if(pthread_create(&pid[connection_count++],NULL,connection_handler,(void *)new_socket)!=0)
Upvotes: 2