pthread_join fails in forking TCP server when handling multiple clients - c

I have to create a multithread TCP/IP server which contains a variable to count the number of clients connected (and those which disconnect) and print the number of clients connected when a client connects to the server.
This is my client.c file:
#define PORT 4444
int main ()
{
int clientSocket;
struct sockaddr_in serverAddress;
char buffer[1024];
ssize_t nread;
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1) {
perror("[-]Errore durante la creazione della socket\n");
exit(-1);
}
printf("[+]Client socket has been created\n");
memset(&serverAddress, '\0', sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = INADDR_ANY;
if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
perror("Errore con la connessione\n");
exit(-1);
}
while (1) {
printf("> ");
fflush(stdin);
scanf("%s", buffer);
if (nread != -1)
buffer[nread] = '\0';*/
if (send(clientSocket, buffer, strlen(buffer), 0) == -1) {
perror("Errore con l'invio");
exit(1);
}
if(strcmp(buffer, ":exit") == 0) {
close(clientSocket);
printf("[-]Disconnected from Server\n");
exit(0);
}
if ( (nread=recv(clientSocket, buffer, sizeof buffer - 1, 0)) <= 0) {
perror("[-]Error in receiving data from server\n");
}
else {
buffer[nread] = '\0';
printf("Server received: %s\n", buffer);
}
}
close(clientSocket);
return 0;
}
and this is my server.c file:
#define PORT 4444
#define MAX_CONNESSIONI 100
typedef struct myStruct {
int clientCollegati;
int clientCheSiSonoScollegati;
pthread_mutex_t mutex; // Creazione del mutex per sincronizzare la struttura
} myStruct;
myStruct *test;
myStruct *initStruct();
void *incrementa(void*);
int main ()
{
int serverSocket, bindStatus;
struct sockaddr_in serverAddress;
int clientSocket;
struct sockaddr_in newAddress;
char buffer[1024];
pid_t child;
socklen_t addrSize;
ssize_t nread;
pthread_t tid;
test = initStruct();
if (pthread_create(&tid, NULL, incrementa, NULL) != 0) {
perror("Errore nella creazione del thread t1\n");
exit(1);
}
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == -1) {
perror("[-]Errore durante la creazione della socket\n");
exit(-1);
}
memset(&serverAddress, '\0', sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = INADDR_ANY;
bindStatus = bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
if (bindStatus == -1) {
perror("[-]Errore durante il binding\n");
exit(1);
}
printf("[+]Bind to port %d\n", PORT);
if (listen(serverSocket, MAX_CONNESSIONI) != -1) {
printf("Listening . . .\n\n");
}
else {
perror("[-]Error during listening\n");
exit(1);
}
while (1) {
clientSocket = accept(serverSocket, (struct sockaddr*)&newAddress, &addrSize);
if (clientSocket == -1) {
exit(-1);
}
printf("%s:%d joined\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port));
if (pthread_join(tid, NULL)) { // returns 3
perror("pthread_join error\n");
exit(1);
}
printf("There is/are %d client(s) connected\n", test->clientCollegati);
child = fork();
if (child == 0) {
close(serverSocket);
while (1) {
if ( (nread=recv(clientSocket, buffer, sizeof buffer - 1, 0)) <= 0) {
perror("[-]Error in receiving data from server\n");
}
else {
buffer[nread] = '\0';
}
if (strcmp(buffer, ":exit") == 0) {
printf("%s:%d left\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port));
break;
}
else {
printf("%s:%d wrote: %s\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port), buffer);
send(clientSocket, buffer, strlen(buffer), 0);
bzero(buffer, sizeof(buffer));
}
}
}
}
close(clientSocket);
return 0;
}
myStruct *initStruct()
{
struct myStruct *ptr = malloc(sizeof(myStruct));
ptr->clientCollegati = 0;
ptr->clientCheSiSonoScollegati = 0;
pthread_mutex_init(&ptr->mutex, NULL); // inizializzazione dinamica del mutex
return ptr;
}
void *incrementa(void *ptr)
{
pthread_mutex_lock(&test->mutex);
test->clientCollegati++;
pthread_mutex_unlock(&test->mutex);
pthread_exit(0);
}
Unfortunately this seems not to work properly, ans you can see server output and here client1 and here client2 output
Where's the mistake? I suppose that the problem is when tid finish and a second call to that pthread_join is invoked to a non-existent thread (because there is a single thread)

Your code logic is wrong. You are doing a single pthread_create() and then multiple pthread_join(). If you want to increment the values for every connected client you have to do one pthread_create() after every single successful accept(), followed by one pthread_join(). Note: all this must happen before the call to fork().
Where's the mistake? I suppose that the problem is when tid finish and a second call to that pthread_join is invoked to a non-existent thread (because there is a single thread)
That's exactly what happens. In your current program, the first pthread_join() is successful, and any successive call fails with errno 3 (no such process) because the thread doesn't exist anymore. So you already figured this out. Why are you creating one thread but joining it multiple times if you know that's wrong?
The way your program is written (fork after the increment) also means that there really is no reason at all to use threads to do the increment, and you don't even need the mutex, since only one single thread will access the value at any given time. In other words, your server isn't multithreaded at all. If you only want to do this as an experiment that's ok, but it doesn't make much sense.
What you probably want to do (to have a multithreaded server) is to have one thread per client instead of forking each time, with the client code in the thread function (in that case having a mutex makes sense). Beware though that this does not scale well for large numbers of clients (in general, the classical fork() approach is better, in which case you really don't need any thread).

Related

Bad Address when reading from sockets in C

i'm facing a problem that i m not able to debug (it seems), let me explain the situation. I have a server that do something and 10 clients to connect. To test the code i use the same machine to host and connect the server and clients. Now, it seems that sometimes i m able to connect a random number of clients, like 4 and during the fifth connection the client side, after a good connection with the server, when i try to read from socket it gives me Bad address.
Now this number seems pretty casual, infact this error on the client side is given sometimes during the third connection, sometimes during the sixth connection and rarely never when i try to connect 10 clients. anyway most of the time this error occurs during the fifth connection.
Here the codes of server and client
Client:
void contact_server(int sockfd, int buffer_size, int reading_pipe, int writing_pipe) {
float* buff = (float*)calloc(buffer_size,sizeof(float));
int ret = 0;
while(1){
ret = 0;
while(ret == 0){
if(sizeof(float)*buffer_size <= sizeof(float)*2048){
ret = read(sockfd, buff, sizeof(float)*buffer_size);
if(ret == -1){
printf("(from server) Error description is: %s\n",strerror(errno));
exit(0);
}
}
else{
long long unsigned int sum = 0;
ret = read(sockfd, buff, sizeof(float)*2048);
if(ret == -1){
printf("(from server) Error description is : %s\n",strerror(errno));
exit(0);
}
sum+=ret;
int count;
for(count = 2048; sum < sizeof(float)*buffer_size; count+=2048, sum+=ret){
if(buffer_size-count < 2048){
ret = read(sockfd, &buff[count], sizeof(float)*(buffer_size-count));
if(ret == -1){
printf("(from server) Error description is : %s\n",strerror(errno));
exit(0);
}
}
else{
ret = read(sockfd, &buff[count], sizeof(float)*2048);
if(ret == -1){
printf("(from server) Error description is : %s\n",strerror(errno));
exit(0);
}
}
}
}
}// waiting for server
ret = write(writing_pipe,buff, sizeof(float)*buffer_size);// writing to parent process
if(ret == -1){
printf("(to parent) Error description is : %s\n",strerror(errno));
exit(0);
}
ret = 0;
while(ret == 0){
ret = read(reading_pipe, buff, sizeof(float)*buffer_size);
if(ret == -1){
printf("(from parent) Error description is : %s\n",strerror(errno));
exit(0);
}
}// waiting for parent process
ret = write(sockfd,buff, sizeof(float)*buffer_size);// writing to server
if(ret == -1){
printf("(to server) Error description is : %s\n",strerror(errno));
exit(0);
}
}
free(buff);
}
/* See server.c for more specific details
*
*
* Inputs:
*
* # int port:= the port of the server
* # char* server_address:= the server address
* # int buffer_size:= the buffer size written by the server and parent process
* # int reading_pipe:= to read from parent
* # int writing_pipe:= to write to parent
* */
int run_client(int port, char* server_address, int buffer_size, int reading_pipe, int writing_pipe){
int sockfd, connfd;
struct sockaddr_in servaddr, cli;
int sockaddr_len = sizeof(struct sockaddr_in);
// socket create and varification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
fprintf(stderr,"Error: socket creation failed...\n");
exit(1);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(server_address);
servaddr.sin_port = htons(port);
// connect the client socket to server socket
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) {
printf("connection with the server failed...\n");
exit(0);
}
else
printf("connected to the server..\n");
// function for chat
contact_server(sockfd,buffer_size,reading_pipe,writing_pipe);
// close the socket
close(sockfd);
return 0;
}
Server:
void* server_thread(void* _args) {
// depacking args
thread_args_server* args = (thread_args_server*) _args;
float* buff = (float*)calloc(args->buffer_size,sizeof(float));
int ret;
while(1){
ret = 0;
while(ret == 0){
ret = read(args->reading_pipe, buff, sizeof(float)*args->buffer_size);
if(ret == -1){
printf("Error description is : %s\n",strerror(errno));
exit(0);
}
}// waiting for parent process
ret = write(args->client_desc,buff, sizeof(float)*args->buffer_size);// writing to client
if(ret == -1){
printf("Error description is : %s\n",strerror(errno));
exit(0);
}
ret = 0;
while(ret == 0){
if(sizeof(float)*args->buffer_size <= sizeof(float)*2048){
ret = read(args->client_desc, buff, sizeof(float)*args->buffer_size);
if(ret == -1){
printf("Error description is : %s\n",strerror(errno));
exit(0);
}
}
else{
long long unsigned int sum = 0;
ret = read(args->client_desc, buff, sizeof(float)*2048);
if(ret == -1){
printf("Error description is : %s\n",strerror(errno));
exit(0);
}
sum+=ret;
long long unsigned int count;
for(count = 2048;sum < sizeof(float)*args->buffer_size; count+=2048, sum+=ret){
if(args->buffer_size-count < 2048){
ret = read(args->client_desc, buff, sizeof(float)*(args->buffer_size-count));
if(ret == -1){
printf("Error description is : %s\n",strerror(errno));
exit(0);
}
}
else{
ret = read(args->client_desc, buff, sizeof(float)*2048);
if(ret == -1){
printf("Error description is : %s\n",strerror(errno));
exit(0);
}
}
}
}
}// waiting for client
ret = write(args->writing_pipe,buff, sizeof(float)*args->buffer_size);// writing to parent process
if(ret == -1){
printf("Error description is : %s\n",strerror(errno));
exit(0);
}
}
free(buff);
return NULL;
}
/* This function creates a server on your current ip address on the port: port,
* accept a maximum number of connections = max_num_conn, and create each thread per connection.
* each thread read a float vector from a client and writes on the writing_pipes[i] this vector, then
* wait for a float vector from reading_pipe[i] and send this vector to the client.
* The ideal situation is: client -> compute some instances of the mini batch, send to server the partial derivatives
* the thread of the client on the server side read these partial derivatives, send back to the father process with writing pipes,
* the parent process sum up all these partial derivatives, update the model, send back to the thread the model updated, the thread
* send to the client and the client goes on and compute again the new partial derivatives, and so on...
*
* Inputs:
*
* # int port:= the server port
* # int max_num_conn:= the maximum number of connections accepted by the server
* # int* reading_pipes:= a pipe writing for float vector to the thread
* # int* writing_pipes:= where the thread write its vector
* # int buffer_size:= the buffer of the vector
*
* */
int run_server(int port, int max_num_conn, int* reading_pipes, int* writing_pipes, int buffer_size, char* ip){
int socket_desc, client_desc,sockaddr_len = sizeof(struct sockaddr_in),c = 1;
int ret;
struct sockaddr_in server_addr;
struct sockaddr_in* client_addr;
struct sockaddr_in* client_addr2;
bzero(&server_addr, sizeof(server_addr));
inet_pton(AF_INET, ip, &(&server_addr)->sin_addr);
// socket creation
socket_desc = socket(AF_INET,SOCK_STREAM,0);
if(socket_desc == -1){
fprintf(stderr,"Error: can't create socket\n");
exit(1);
}
// Which connection can accept
server_addr.sin_addr.s_addr = INADDR_ANY;
// Ip family
server_addr.sin_family = AF_INET;
// Port
server_addr.sin_port = htons(port);
// Handling crash case to reuse the descriptor
ret = setsockopt(socket_desc,SOL_SOCKET,SO_REUSEADDR,&c,sizeof(int));
if(ret == -1){
fprintf(stderr,"Error: setsockopt failed..\n");
exit(1);
}
// Binding newly created socket to given IP and verification
if ((bind(socket_desc, (struct sockaddr *)&server_addr, sizeof(server_addr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// listen on tot number of connections
ret = listen(socket_desc,max_num_conn);
if(ret == -1){
fprintf(stderr,"Error, listen failed\n");
exit(1);
}
int i = 0;
while(1){
client_addr = calloc(1,sizeof(struct sockaddr_in));
client_desc = accept(socket_desc,(struct sockaddr*)&client_addr,(socklen_t*)&sockaddr_len);
if((client_desc == 1 && errno == EINTR)) continue;
thread_args_server* thread = (thread_args_server*)malloc(sizeof(thread_args_server));
thread->idx = i;
thread->client_desc = client_desc;
thread->client_addr = client_addr;
thread->reading_pipe = reading_pipes[i];
thread->writing_pipe = writing_pipes[i];
thread->buffer_size = buffer_size;
pthread_t t;
pthread_create(&t,NULL,server_thread,thread);
pthread_detach(t);
printf("connected client id: %d\n",i);
i++;
}
pthread_exit(NULL);
return 0;
}
The error is given by ret = read(sockfd, &buff[count], sizeof(float)*(buffer_size-count)); on client side:
Thank you for the help

C server client Bad file descriptor

I have been figuring out why the below code give a bad descriptor for the whole day now. Below is the server code, most of it references to Beej's guide.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include "CountryData.c"
//This function determine if address is IPv4 or IPv6 IP address
void *getAddr_Type(struct sockaddr *sa) {
if (sa->sa_family == AF_INET) { //If IPv4
return &(((struct sockaddr_in*)sa)->sin_addr);
}
else //if IPv6
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
void sigchld_handler(int s)
{
// waitpid() might overwrite errno, so it is stored in a variable first:
int saved_errno = errno;
while(waitpid(-1, NULL, WNOHANG) > 0);
errno = saved_errno;
}
int main(void){
readData(); //Read from CountryData.c
int status, sockfd, client_sockfd;
int pid; //fork return value
char buffer[1000];
int bytecount;
struct addrinfo hints, *res, *serverInfo; //res points to linked list of "struct addrinfo"; serverInfo also points to linked list of "struct addrinfo" for use in for loop.
struct sockaddr_storage client_addr; //Address information of the client
struct sigaction sa;
socklen_t address_size; //Initialize size of address
char i[INET6_ADDRSTRLEN]; //INET6_ADDRSTRLEN macro is used to store maximum length of IPv6. Since IPv4 is definitely shorter than IPv6, "INET_ADDRSTRLEN" is not used.
memset(&hints, 0, sizeof(hints)); //emptying the structure
//Pass in value into "addrinfo" struct
hints.ai_family = AF_INET; //Using IPv4
hints.ai_socktype = SOCK_STREAM; //Using TCP
hints.ai_flags = AI_PASSIVE; //AI_PASSIVE = Own IP address
status = getaddrinfo(NULL, "8888", &hints, &serverInfo); //Initialising status return value and also passing in values to getaddrinfo().
//IP address is set to null. This will be filled in automatically by AI_PASSIVE.
if (status != 0) {
fprintf(stderr, "Error: %s\n", gai_strerror(status));//gai_strerror to print human readable error
exit(1);
}
//Loop through all results and bind to the first
for (res = serverInfo; res != NULL; res = res->ai_next) {
//(1)Initializing socket
if ((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) { //Show error message if initializing socket file descriptor fails
perror("Socket");
continue;
}
int optValue=1;
if ((setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optValue, sizeof(int))) == -1) {
perror("Socket options");
exit(1);
} //(2)setting socket options. "SO_REUSEADDR" to prevent "Address already in use" and to allow reuse of the port
if ((bind(sockfd, res->ai_addr, res->ai_addrlen)) == -1) { //(3) Binding to local address and port
close(sockfd);
perror("Bind");
continue;
}
break;
}
freeaddrinfo(serverInfo); //Freeing "serverInfo" linked list
//However, if linked list is still empty, print error.
if (res == NULL) {
fprintf(stderr, "Error! Server is unable to bind.\n");
exit(1);
}
//If unable to listen, print error.
if ((listen(sockfd, 8)) == -1) { //(4) Listen for client connections, maximum of 8 waiting in queue
perror("Listen");
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("Running server program 'server' ... \n\n\nCountry Directory Server Started! PID: %d\n", getpid());
for(;;) //infinite loop for server to wait for client requests
{
memset(buffer, 0, 1000);
address_size = sizeof(client_addr);
client_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &address_size);
if (client_sockfd == -1) {
perror("Accept");
close(client_sockfd);
exit(1);
}
inet_ntop(client_addr.ss_family, getAddr_Type((struct sockaddr *)&client_addr), i, sizeof(i));//retrieving IP address. "inet_ntop" is used for IPv6 compatibility.
printf("-------------------------------------------------------\n");
printf("Connection received from: %s\n\n", i);
if ((pid = fork()) == -1){ //Starts forking
perror("Failed to fork");
close(sockfd);
}
else if (pid == 0){ //child process
close(sockfd);//Child doesn't need this socket
memset(buffer, 0, 1000); //clear the buffer
if ((bytecount = recv(client_sockfd, buffer, 1000, 0)) == -1){//Receiving Client's input
perror("Server unable to receive");
close(client_sockfd);
exit(0);
}
else if ((strcasecmp(buffer, "END")) == 0){ //Nested If-statement; If client sends "end"
close(client_sockfd);
exit(0);
break;
}
else if (bytecount == 0) { //If "recv" returns 0, client has closed the connection
printf("Client (%d) has closed the connection.\n", getpid());
close(client_sockfd);
exit(0);
break;
}else {
printf("%s", buffer);
printf("%d", client_sockfd);
}
}
close(client_sockfd);
} //end of infinite while loop
}//End of main function
It successfully read client's input and print it out on the screen for the first for(;;) loop. The after the 2nd iteration, it shows Bad file descriptor
Below is the output in the server terminal after typing Hi in the client.
Johnny$ server
Running server program 'server' ...
Country Directory Server Started! PID: 18386
-------------------------------------------------------
Connection received from: 127.0.0.1
Accept: Bad file descriptor
Hi4
The number 4 is printing out the return value of the child file descriptor. This means that the loop ran once, then return an error. My expected output is simply to keep listening for the client's input and the server should constantly spit out what the client typed.
I am new to this server thing and am really having a major headache right getting this to work. Any help will be greatly appreciated.
Below is the client's code, if you're interested.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>
void welcome()
{
printf("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
printf(" Welcome to the Country Info Directory Service! \n");
printf(" ---------------------------------------------- \n");
printf("Usage :\n\n");
printf("1) At the '>' prompt, type in the name of the country\n");
printf(" you wish to search\n\n");
printf("2) To end program, type in 'end'\n");
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n");
}
//This function determine if address is IPv4 or IPv6 IP address
void *getAddr_Type(struct sockaddr *sa) {
if (sa->sa_family == AF_INET) { //If IPv4
return &(((struct sockaddr_in*)sa)->sin_addr);
}
else //if IPv6
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[]) {
int sockfd, numOfBytes;
int retrieveInfo;
char buf[100];
struct addrinfo hints, *res, *serverInfo;
char i[INET6_ADDRSTRLEN]; //INET6_ADDRSTRLEN macro is used to store maximum length of IPv6. Since IPv4 is definitely shorter than IPv6, "INET_ADDRSTRLEN" is not used.
if (argc != 2){
printf("Please enter in this format:\n'client':server-host-name\nFor example, if your hostname is vmwubuntu, please type:\nclient vmwubuntu [Enter]\n\n");
exit(1);
}
welcome();
memset(&hints, 0, sizeof(hints)); //emptying the structure
//Pass in value into "addrinfo" struct
hints.ai_family = AF_INET; //Using IPv4
hints.ai_socktype = SOCK_STREAM; //Using TCP
retrieveInfo = getaddrinfo(argv[1], "8888", &hints, &serverInfo);
if(retrieveInfo != 0) {
printf("Fail to retrieve address!");
}
//Loop through all results and bind to the first
for (res = serverInfo; res != NULL; res = res->ai_next) {
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); //(1)Initializing socket
if (sockfd == -1) { //Show error message if initializing socket file descriptor fails
perror("Socket");
continue;
}
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == -1) { //Retrieving values from "struct addrinfo" through "res" pointer
//close(sockfd);
perror("Connection");
continue;
}
break;
}
if (res == NULL) {
printf("Failed to connect to server\n");
exit(1);
}
char input[1000];
char receive[1000];
for(;;)
{
memset(input, '\0', 1000); //Initialize buffer size to store user input
printf("Enter Country > ");
fgets(input, 1000, stdin); //Take in user input with 1000 as the buffer size
input[strlen(input) - 1] = '\0'; //Stripping the null terminator away
if (strcasecmp(input, "END") == 0){ //If user enters "end"(case is ignored), close the file descriptor and exit
close(sockfd);
exit(0);
}
else {//SEND
if((numOfBytes = send(sockfd, input, strlen(input), 0)) == -1){ //start of nested if statement
perror("Unable to send");
exit(1);
}
else if (numOfBytes != strlen(input)){ //If string is not sent in full
perror("Send");
close(sockfd);
exit(1);
}else{//for testing purposes
printf("%d\n",strlen(input));//for testing purpose
printf("%d\n", numOfBytes); //for testing purpose
}//End of nested if statement
}
}//End of for infinite loop
} //End of main()
Your child process appears to be not exiting, and instead proceeding with the same code as the parent. Then, you try to call accept with the closed file descriptor.
This is why I always put the child code in its own function, and always call _exit() immediately following. Note that I use _exit() instead of exit() to ensure that no parent atexit handlers are executed.
Furthermore, it helps to include PIDs in your log messages. Try using something like this:
#define INFO(fmt, ...) fprintf(stderr, "[%d] %s" fmt, getpid(), __FUNCTION__, __VA_ARGS__)
...
INFO("x=%d\n", x);
The child process in the sever side will try to accept the same fd.
How about to add a infinite loop before
else if (pid == 0){ //child process
close(sockfd);//Child doesn't need this socket
memset(buffer, 0, 1000); //clear the buffer
for (;;) {
if ((bytecount = recv(client_sockfd, buffer, 1000, 0)) == -1){//Receiving Client's input
perror("Server unable to receive");
close(client_sockfd);
exit(0);
}
else if ((strcasecmp(buffer, "END")) == 0){ //Nested If-statement; If client sends "end"
close(client_sockfd);
exit(0);
break;
}
else if (bytecount == 0) { //If "recv" returns 0, client has closed the connection
printf("Client (%d) has closed the connection.\n", getpid());
close(client_sockfd);
exit(0);
break;
}else {
printf("%s", buffer);
printf("%d", client_sockfd);
}
}
}

Static variable in C

I have this program that is a part of a server with tcp protocol, that gets a number from the client and uses it in another function.
Also I have a static int type variable that i want to count each time the server gets a message from a client, but each time it does not keep its value;
The variable is counter
Can you guys tell me why this is happening?
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// used port
#define PORT 1114
// error code
extern int errno;
static int counter;
int main ()
{
struct sockaddr_in server; // structure used by server
struct sockaddr_in from;
char message[100]; //message received from client
int socketDescriptor; //socket descriptor
//creating socket
if ((socketDescriptor = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("[server]Error at socket\n");
return errno;
}
//preparing data structures
bzero (&server, sizeof (server));
bzero (&from, sizeof (from));
//filling structures
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl (INADDR_ANY);
server.sin_port = htons (PORT);
//attach socket to descriptor
if (bind (socketDescriptor, (struct sockaddr *) &server, sizeof (struct sockaddr)) == -1)
{
perror ("[server]Error at bind\n");
return errno;
}
//server is listening
if (listen (socketDescriptor, 2) == -1)
{
perror ("[server]Error at listen\n");
return errno;
}
/serving concurrent the clients
while (1)
{
int client;
int length = sizeof (from);
printf ("[server]Waiting at port %d...\n",PORT);
fflush (stdout);
//accepting client
client = accept (socketDescriptor, (struct sockaddr *) &from, &length);
counter ++;
switch(fork())
{
case -1:
perror("fork err\n");
exit(2);
case 0:
//error if failed connection
if (client < 0)
{
perror ("[server]Error at accept\n");
continue;
}
//conenction established
bzero (message, 100);
printf ("[server]Waiting for message...\n");
fflush (stdout);
//reading message
if (read (client, message, 100) <= 0)
{
perror ("[server]Error at read\n");
close (client); //closing connection
continue; //keep listening
}
printf ("[server]Message was received%s\n", message);
//this is where I want to increment counter, when I want to verify message
int number;
number = atoi(message);//convert char to int
printf("The number is: %d\n", number);//print number
printf("The counter is : %d\n", counter);
fflush(stdout);
exit(2);
}
close (client);
} /* while */
} /* main */
Just move counter++ to the parent process. When the child process starts it gets a copy of counter and the one you modify does not affect it's copy (original actually) in the parent process. If you update it in the parent process you will achieve what you want.
int main(int argc, char ** argv)
{
int number;
int listenfd, connfd, n;
pid_t childpid;
socklen_t clilen;
char message[MAXLINE], answer[MAXLINE];
struct sockaddr_in clientaddr, serveraddr;
int counter;
counter = 0;
// create socket
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("ERROR at creating socket\n");
exit(2);
}
// preparation of socket address
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(PORT);
// bind the socket
bind(listenfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr));
// listen to the socket
listen(listenfd, LIMIT);
printf("Server running, waiting for connections at port : %d\n", PORT);
while (1)
{
clilen = sizeof(clientaddr);
// accept a connection
connfd = accept(listenfd, (struct sockaddr *) &clientaddr, &clilen);
printf("Recieved guest\n");
switch (fork())
{
case -1:
perror("fork err\n");
exit(2);
case 0:
/* eroare la acceptarea conexiunii de la un client */
if (connfd < 0)
{
perror("[server]Eroare la accept().\n");
continue;
}
/* s-a realizat conexiunea, se astepta mesajul */
bzero(message, 100);
printf("[server]Asteptam mesajul...\n");
fflush(stdout);
/* citirea mesajului */
if (read(connfd, message, 100) <= 0)
{
perror("[server]Eroare la read() de la client.\n");
close(connfd); /* inchidem conexiunea cu clientul */
continue; /* continuam sa ascultam */
}
printf ("[server]Message was received...%s\n", message);
fflush(stdout);
number = atoi(message);
printf("The number is: %d\n", number);
printf ("%d\n", counter + 1);
_exit(0); // The child should not create further grand children
default:
counter++;
break;
}//switch
}//for
close(connfd);
}//main
You appear to be forking before setting the counter. Since forking duplicates the entire process, the copy of counter in each child process is different from the parent.
Sharing variables between applications in C can be tricky, but actually there's a pretty easy fix for your case and it will improve performance too. If you look at your code, you're forking after the connect and then handling, in the child, the possibiliy that the connfd < 0. If you handled that in the parent process, the counter could belong to the parent and could be incremented before the fork.
A few other notes here come to mind. Remember, fork duplicates the parent process, so the children in your case are still within a while(1) loop. When you continue you loop back to the next iteration of the while(1) loop, but this doesn't seem correct; you want the child process to exit when it's done handling the connection. This also means as you accept connections, you fork but the fork never dies - I guess that's more a "process leak" than a memory leak, but will certainly eat up memory. Finally, just to throw it out there, forking to handle each request is probably the slowest way to concurrently handle connections. I've had great success with pthread in this case. Since threads share a process space, the threads can even persist and handle many connections before dying ( put the connections on a queue and have the threads poll it, for example ) becasuse they can continue to share connections with their "parent" ( though it's really a sibling thread in this case).

Server-Client Threading Accept error/leak

I keep getting a "Accept: too many files" error after running my server.c code. Trying to get it to create new threads for clients and limit connections with semaphores.
This is my code:
#define MAX_CLIENTS 30
sem_t s;
void *handle(void *pnewsock);
int sockfd, new_fd, numbytes; // listen on sock_fd, new connection on new_fd
struct sockaddr_in my_addr; // my address information
struct sockaddr_in their_addr; // connector's address information
socklen_t sin_size;
pthread_t thread;
int main(void){
//initialise locks
sem_init(&s, 0, 0);
/* generate the socket */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(true);
}
my_addr.sin_family = AF_INET; // host byte order
my_addr.sin_port = htons(MYPORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP
/* bind the socket to the end point */
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
== -1) {
perror("bind");
exit(true);
}
/* start listnening */
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(true);
}
printf("server starts listening ...\n");
/* Main loop */
while (1) {
sin_size = sizeof(struct sockaddr_in);
if (pthread_create(&thread, NULL, handle, &new_fd) != 0) {
fprintf(stderr, "Failed to create thread\n");
}
}
return 0;
}
void *handle(void *pnewsock){
int value;
sem_getvalue(&s,&value);
while (value >= MAX_CLIENTS){
printf("too many connections");
sem_wait(&s);
}
if (value < MAX_CLIENTS){
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
&sin_size)) == -1) {
perror("accept");
exit(1);
}
printf("server: got connection from %s\n", \
inet_ntoa(their_addr.sin_addr));
char buffer[MAXDATASIZE];
char res[MAXDATASIZE];
memset(buffer, '\0', MAXDATASIZE);
memset(res, '\0', sizeof(res));
if ((numbytes=recv(new_fd, buffer, sizeof(buffer), 0)) == -1) {
perror("recv");
exit(true);
}
else if(numbytes == 0) {
printf("client left");
sem_post(&s);
close(new_fd);
exit(false);
}
else {
buffer[numbytes] = '\0'; // add null terminator
printf("Request: %s\n",buffer);
//search function
}
}
close(new_fd);
exit(false);
return NULL;
}
Can anyone give me some insight to this file leak? Thanks
The main() function is creating pthreads using an infinite loop. Your error is very likely related to this since the loop will keep on creating newer threads.
/* Main loop */
while (1) {
sin_size = sizeof(struct sockaddr_in);
if (pthread_create(&thread, NULL, handle, &new_fd) != 0) {
fprintf(stderr, "Failed to create thread\n");
}
}
What you probably meant was to create one thread for each client. And if that is the case, then the handle() function should call pthread_create() whenever it gets a new client from the accept() call. The server (the socket for which we call listen and accept) does not need multiple threads -- one thread -- which can be the main thread -- is all it needs.

Limiting Clients From Connecting

Trying to limit the amount of client connections in my client-server c application. This is what I have, however it doesn't work. (Doesn't even recognise when max_connections is reached. How can I fix this?
int main(int argc, char *argv[])
{
//fill db
if (obtainDb() == false) {
printf("Database obtain error.\n");
exit(true);
}
//initialise variables
total_connections = 0;
/* generate the socket */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(true);
}
/* generate the end point */
my_addr.sin_family = AF_INET; // host byte order
my_addr.sin_port = htons(MYPORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP
/* bind the socket to the end point */
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
== -1) {
perror("bind");
exit(true);
}
/* start listnening */
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(true);
}
printf("server starts listnening ...\n");
while(true){
sin_size = sizeof(struct sockaddr_in);
if (total_connections == max_connections) {
printf("Max Number of clients connected!\n");
while(total_connections == max_connections);
}
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
&sin_size)) == -1) {
perror("accept");
continue;
}
total_connections++;
printf("server: got connection from %s\n", \
inet_ntoa(their_addr.sin_addr));
userInput();
while(waitpid(-1,NULL,WNOHANG)>0);
}
return false;
}
Thanks
Edit: UserInput():
void userInput(void) {
if (!fork()) { // this is the child process
while(true){
char buffer[MAXDATASIZE];
char res[MAXDATASIZE];
memset(buffer, '\0', MAXDATASIZE);
memset(res, '\0', sizeof(res));
if ((numbytes=recv(new_fd, buffer, sizeof(buffer), 0)) == -1) {
perror("recv");
exit(true);
}
if (numbytes == 0) {
printf("client left");
close(new_fd);
total_connections--;
exit(false);
}
buffer[numbytes] = '\0'; // add null terminator
printf("Request: %s\n",buffer);
search(buffer,res);
}
close(new_fd); // parent doesn't need this
exit(false);
}
close(new_fd);
}
When you fork all variables are copied to the new process. That means that the children have their own copy of total_connections.
Instead of using a variable, you should use wait to find out whether any children have exited.
Forking creates a new instance of your proces, which also means that each variable is copied to the new process. Your initial total_connections will actually never get increased beyond 1.
C fork dealing with global variable
A relatively simple option would be to use threads instead of processes for handling multiple clients simultaneously.

Resources