multithreading in client server chat app in c linux - c

i want to create a client server chat application in c using linux.. i want to create two threads in client and server programms. one for send and other for recv.. iam new to threading .. please let me know how i should create it?
here is my server code..
#include <stdlib.h>
#include <stdio.h>
#include <string.h> //strlen
#include <sys/socket.h>
#include <arpa/inet.h> //inet_addr
#include <unistd.h> //write
#define port 8877
int main(int argc , char *argv[])
{
int socket_desc , client_sock , c , client_reply;
struct sockaddr_in server , client;
char client_message[5000];
char repltocli[6000];
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons( port);
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 9);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
//accept connection from an incoming client
client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
puts("Connection accepted");
puts("press ctrl+c to terminate the application");
while(1)
{
//Receive a message from client
recv(client_sock , client_message , 5000 , 0);
puts("messege recived from client :");
puts(client_message);
memset(client_message, 0, sizeof(client_message));
printf("enter your message : ");
fgets(repltocli, 6000,stdin);
//Send some data
send(client_sock, repltocli , strlen(repltocli) , 0) ;
memset(repltocli, 0, sizeof(repltocli));
}
return 0;
}

For dealing with threads you need to create thread functions, return type should be void * and with/with out an argument. But if you use arguments, arguments should be void *
Thread to receive message-
void *receive_message(){
while(1){
//Receive a message from client
recv(client_sock , client_message , 5000 , 0);
//puts("messege recived from client :"); // Comment this line out. Else it will annoye the user by printing every time
puts(client_message);
memset(client_message, 0, sizeof(client_message));
}
}
Thread to send message-
void *send_message(){
while(1){
// printf("enter your message : "); // Comment this line out. Else it will annoye the user by printing every time
fgets(repltocli, 6000,stdin);
//Send some data
send(client_sock, repltocli , strlen(repltocli) , 0) ;
memset(repltocli, 0, sizeof(repltocli));
}
}
And declare repltocli array, client_sock and client_message array globally, because your threads also needs it!
In your main() declare two pthread_d variable for threads-
int main(){
pthread_d thread_send, thread_recv;
// Do your stuff like socket, bind, listen and accept!
// Create these two threads and make sure that your main program should be alive-
pthread_create(&thread_send, NULL, send_message, NULL);
pthread_create(&thread_recv, NULL, receive_message, NULL);
while(1); // Press ctrl + C to terminate!
return 0;
}
Do this same thing for another side also.

Simple idea is to have each thread on each request.
Algorithm
Loop for the request
When ever you are getting a request ,create a thread to process the data.
Thread function will handle the request
something like bellow will work in server code
while(1)
{
//Get the request
//Create a thread to handle the request
}
Please read about Pthread library for linux.

Related

Multiple client not getting connected and cannot communicate at the same time

Below is the server code which I have written for multiple clients. But if I want to connect it with the second client, I am not able to connect it at the same time. At first I need to close the first client and then only I can connect and communicate with the second client. I think I have some problem while using the pthread_join. Not sure what is the exact problem. I want to make the server work for multiple clients at the same time.
#include<stdio.h>
#include<string.h> //strlen
#include<stdlib.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h> //write
#include<pthread.h> //for thread
#define MAX_CLIENTS 5
//the thread function
void *new_connection_handler(void *);
int main(int argc , char *argv[])
{
int socket_desc , client_sock , c , *new_sock;
struct sockaddr_in server , client;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
bzero (&server.sin_zero, 8);
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
//Listen
listen(socket_desc , MAX_CLIENTS);
//Accept and incoming connection
printf("Waiting for incoming connections\n");
c = sizeof(struct sockaddr_in);
while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
{
printf("Connection accepted");
pthread_t thread_id;
new_sock = malloc(1);
*new_sock = client_sock;
if( pthread_create( &thread_id , NULL , new_connection_handler , (void*) new_sock) < 0)
{
perror("could not create thread");
return 1;
}
printf("Handler assigned\n");
}
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
return 0;
}
void *new_connection_handler(void *socket_desc)
{
//Get the socket descriptor
int sock = *(int*)socket_desc;
int read_size;
char *message , client_message[2000];
//Send some messages to the client
message = "This is connection handler\n";
write(sock , message , strlen(message));
message = "Type something \n";
write(sock , message , strlen(message));
//Receive a message from client
while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
{
//Send the message back to client
write(sock , client_message , strlen(client_message));
}
if(read_size == 0)
{
printf("Client disconnected\n");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
//Free the socket pointer
free(socket_desc);
return 0;
}
There is no need to join all threads. Detached threads are appropriate for this task.
I assume you are really calling pthread_join inside the while (accept(..)) loop, otherwise your description doesn't make much sense. If this is the case, just replace it with pthread_detach.
If you want to wait for all the threads to terminate before exiting, use a pthreads condition variable to count active threads. In your case the main program never exits so you can simply ignore the issue.

Socket Server Hangs

This socket server has some error in it, most likely pthread related. If this keeps accepting client connections, after a while it will start hanging. It doesn't seems to be a memory leak because the memory occupied by the program remains the same but when I connect with a telnet client it will just hang and does not do anything.
It will still get to the
puts("Handler assigned");
part but then it does nothing. Any ideas what can cause this?
/*
C socket server example, handles multiple clients using threads
*/
#include<stdio.h>
#include<string.h> //strlen
#include<stdlib.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h> //write
#include<pthread.h> //for threading , link with lpthread
//the thread function
void *connection_handler(void *);
int main(int argc , char *argv[])
{
int socket_desc , client_sock , c , *new_sock;
struct sockaddr_in server , client;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
{
puts("Connection accepted");
pthread_t sniffer_thread;
new_sock = malloc(1);
*new_sock = client_sock;
if( pthread_create( &sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0)
{
perror("could not create thread");
return 1;
}
//Now join the thread , so that we dont terminate before the thread
//pthread_join( sniffer_thread , NULL);
puts("Handler assigned");
}
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
return 0;
}
/*
* This will handle connection for each client
* */
void *connection_handler(void *socket_desc)
{
//Get the socket descriptor
int sock = *(int*)socket_desc;
int read_size;
char *message , client_message[2000];
//Send some messages to the client
message = "Greetings! I am your connection handler\n";
write(sock , message , strlen(message));
message = "Now type something and i shall repeat what you type \n";
write(sock , message , strlen(message));
//Receive a message from client
while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
{
//Send the message back to client
write(sock , client_message , strlen(client_message));
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
//Free the socket pointer
free(socket_desc);
return 0;
}
Don't assume that writing to a socket writes all bytes. Always check the return value. Instead of write use your own sendbuf() function that writes to the socket in a loop and returns only when all bytes of your buffer has been sent.`
You have to join every created thread exactly once otherwise you leak a thread handle. If you don't want to join a thread then you have 2 options:
Create it as detached by specifying the attribute parameter for pthread in which you tell pthread_create() to create the thread as detached. Search for tutorials that use the pthread_attr_setdetachstate() function to find out how to do this.
After creating the thread call pthread_detach() on it to tell the pthread library that you don't want to join the thread.
Since you receive and send in turns if both the server and the client are using blocking sockets it may happen that the send buffers fill up on both ends if the client tries to send a large enough buffer and it results in a deadlock. Aid this with one of the following solutions:
Use setsockopt() in your server to setup send/receive timeouts with the SO_SNDTIMEO and SO_RCVTIMEO socket options and optionally tweak the send/receive buffer sizes with SO_SNDBUF SO_RCVBUF options if you want but I wouldn't set these latter two options without reasons.
At least one of the peers (preferably the server) should receive and send at the same time using asnyc socket.
Use read_size instead of strlen(client_message) when sending back the message to the client. Assuming that the received chunk is zero terminated is wrong even if the client has sent a zero terminated message because you may receive it as fragmented.

Socket server close the connection for command

I trying to modify the following code which is a simple multithreaded socket server that if a client issue a QUIT command then it will actually close the connection.
/*
C socket server example, handles multiple clients using threads
*/
#include<stdio.h>
#include<string.h> //strlen
#include<stdlib.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h> //write
#include<pthread.h> //for threading , link with lpthread
//the thread function
void *connection_handler(void *);
int main(int argc , char *argv[])
{
int socket_desc , client_sock , c , *new_sock;
struct sockaddr_in server , client;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
{
puts("Connection accepted");
pthread_t sniffer_thread;
new_sock = malloc(1);
*new_sock = client_sock;
if( pthread_create( &sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0)
{
perror("could not create thread");
return 1;
}
//Now join the thread , so that we dont terminate before the thread
//pthread_join( sniffer_thread , NULL);
puts("Handler assigned");
}
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
return 0;
}
/*
* This will handle connection for each client
* */
void *connection_handler(void *socket_desc)
{
//Get the socket descriptor
int sock = *(int*)socket_desc;
int read_size;
char *message , client_message[2000];
//Send some messages to the client
message = "Greetings! I am your connection handler\n";
write(sock , message , strlen(message));
message = "Now type something and i shall repeat what you type \n";
write(sock , message , strlen(message));
//Receive a message from client
while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
{
//Send the message back to client
write(sock , client_message , strlen(client_message));
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
//Free the socket pointer
free(socket_desc);
return 0;
}
What I did is to insert a break into the while loop to the connection handler thread (which works) then before the
free(socket_desc);
I added
close(socket_desc);
as well to close the connection. This generates a compiler error and also the server crashes when it reaches this point.
com.c: In function ‘connection_handler’: com.c:134:5: warning: passing
argument 1 of ‘close’ makes integer from pointer without a cast
[enabled by default]
Since (in your second block of code) you seem to be using sock_desc as a void pointer to what you know is actually an int, and sock as an int obtained by dereferencing that, you should be calling
close(sock);
As close(), like the other socket functions you have used, takes a file descriptor (which you can think of as a slightly arbitrary "file number" provided by the system) as its argument, rather than a pointer.

Chatroom in C / Socket programming in Linux

I have a simple server and client C code to do a chatroom for multiclients using threads (pthread library). The problem I've been having is that I can't think a way of making the server write every message that a client sends over the socket into all other clients. I've read other similar posts in here and it was helpless. Please help me I need to do this for school. I'll send both codes right away.
Server.c:
#include<stdio.h>
#include<string.h> //strlen
#include<stdlib.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h> //write
#include<pthread.h> //for threading , link with lpthread
void *connection_handler(void *);
int main(int argc , char *argv[])
{
int socket_desc , new_socket , c , *new_sock;
struct sockaddr_in server , client;
char *message;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("bind failed");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
while( (new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
{
puts("Connection accepted");
pthread_t sniffer_thread;
new_sock = malloc(1);
*new_sock = new_socket;
if( pthread_create( &sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0)
{
perror("could not create thread");
return 1;
}
//Now join the thread , so that we dont terminate before the thread
//pthread_join( sniffer_thread , NULL);
puts("Handler assigned");
}
if (new_socket<0)
{
perror("accept failed");
return 1;
}
return 0;
}
/*
* This will handle connection for each client
* */
void *connection_handler(void *socket_desc)
{
//Get the socket descriptor
int sock = *(int*)socket_desc;
int read_size;
char *message , client_message[2000];
//Receive a message from client
while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
{
//Send the message back to client
write(sock , client_message , strlen(client_message));
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
//Free the socket pointer
free(socket_desc);
return 0;
}
Client.c
#include<stdio.h> //printf
#include<string.h> //strlen
#include<sys/socket.h> //socket
#include<arpa/inet.h> //inet_addr
int main(int argc , char *argv[])
{
int sock;
struct sockaddr_in server;
char message[1000] , server_reply[2000];
//Create socket
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1)
{
printf("Could not create socket");
}
puts("Socket created");
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 8888 );
//Connect to remote server
if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("connect failed. Error");
return 1;
}
puts("Connected\n");
puts("Bienvenido al Chatroom, puedes empezar a escribir en la sala!");
//keep communicating with server
while(1)
{
printf("Enter message: ");
fgets(message, sizeof(message),stdin);
//scanf("%s" , message);
//Send some data
if( send(sock , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
//Receive a reply from the server
if( recv(sock , server_reply , 2000 , 0) < 0)
{
puts("recv failed");
break;
}
printf("Server Reply: %s\n", server_reply);
server_reply[0]='\0';
}
close(sock);
return 0;
}
These programs are very simple, the client sends what the user writes in console and the server send the same message back. I just need the server to send the same message to every thread (client) connected (not only the one who sent the original message).
I know this is long for anyone to care, but if you can, I'll be glad to get some help :)
You need a global table of all clients, protected by a mutex. When a new client connects, add them to the global table of clients. When a client disconnects, remove them from the global table.
When a client sends a message, acquire the lock on the global table and traverse it. Send the message to all clients (other than the one that sent the message, if you don't want to echo a message back to its source).
This is a gross oversimplification of how real servers do it. But it should be enough to get you started.

C echo server, doesnt work well after echoing a sentence

while testing this code i figured out this echo server work well for one word.if try to echo a sentence server also echo it but after that it echo inputs with previous echoed sentence last word. i cleared buffers using memset but still get same problem. cannot understand where is the problem.
server code
#include<stdio.h>
#include<string.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h> //write
int main(int argc , char *argv[])
{
int socket_desc , client_sock , c , read_size;
struct sockaddr_in server , client;
char client_message[2000];
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
//accept connection from an incoming client
client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
puts("Connection accepted");
//Receive a message from client
memset(client_message, 0, sizeof(client_message));
while( (read_size = recv(client_sock , client_message , 2000 , 0)) > 0 )
{
//Send the message back to client
write(client_sock , client_message , strlen(client_message));
memset(client_message, 0, sizeof(client_message));
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
return 0;
}
client code :
#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
int main(int argc , char *argv[])
{
int sock;
struct sockaddr_in server;
char message[1000] , server_reply[2000];
//Create socket
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1)
{
printf("Could not create socket");
}
puts("Socket created");
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 8888 );
//Connect to remote server
if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("connect failed. Error");
return 1;
}
puts("Connected\n");
//keep communicating with server
while(1)
{
printf("Enter message : ");
//scanf("%s" , message);
fgets(message, sizeof(message), stdin);
//Send some data
if( send(sock , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
//Receive a reply from the server
if( recv(sock , server_reply , 2000 , 0) < 0)
{
puts("recv failed");
break;
}
puts("Server reply :");
puts(server_reply);
memset(message, 0, sizeof(message));
memset(server_reply, 0, sizeof(server_reply));
}
close(sock);
return 0;
}
Sample outputs
Enter message : sample
Server reply :
sample
Enter message : sample test
Server reply :
sample test
Enter message : gamer
Server reply :
gamer
test
Enter message : pro
Server reply :
pro
r
test
Your problem is this line:
write(client_sock , client_message , strlen(client_message));
Your client does not send a \0 terminator. So if you first send a long string, then a short one then the short one will overwrite just the beginning. Change that to:
write(client_sock , client_message , read_size); // send exactly as much as you got
And on the client side print only as much as was received:
ssize_t answer_size;
if((answer_size = recv(sock , server_reply , sizeof(server_reply) , 0)) < 0)
{
puts("recv failed");
break;
}
printf("Server reply :\n%.*s\n", answer_size, server_reply);
Also please keep in mind that for implementation specific reasons you may or not get everything that was sent with the first recv and it is recommended to run it in a while loop (with nonblocking mode if nessesary). Same goes for send.
The send() and receive() functions are both blocking and will only return when the socket closes or a full buffer is processed. Your client code defines message[1000], while your server code waits for a client_message[2000] array before responding.
Unless you want to end up using select() or asynchronous I/O to recover the actual network-level messages you will need to either prefix the message with a length that allows you to limit the reads to the actual data, or to use a terminator and then process the incoming data character by character. OF these the most straight-forward is to include an explicit message length early into the stream at the start of each exchange.
The incorrect responses are because you reuse the sending buffer without clearing it. If you include a memset(message, 0, 1000) at the beginning of the while() you will avoid the problem.
The underlying problem is that your client will always send the entire buffer even if only a few characters contain data of value. The effect of this on your application will depend on the network speed, message frequency, number of parties in the landscape and host capacity to tolerate the inefficiency.

Resources