I have updated my code to this based on research:
while (number_of_connections--) {
client_sock = socket(AF_INET , SOCK_STREAM , 0);
if (connect(client_sock , (struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("connect failed. Error");
}
printf("socket %d created\n", client_sock);
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;
}
}
Then I'm handling it with this function:
void *connection_handler(void *socket_desc)
{
//Get the socket descriptor
int sock = *(int*)socket_desc;
int read_size, cursor;
char *message , client_message[2000];
//Send some messages to the client
char handshakeBuf[sizeof(handshake)];
memcpy(handshakeBuf, &handshake, sizeof(handshake));
handshake.a++;
handshake.c = 0xac;
handshake.d = 0x0d;
//Send some data
if( send(sock , handshakeBuf , sizeof(handshakeBuf) , 0) < 0)
{
puts("Send failed");
}
//keep communicating with server
while(1)
{
//Receive a reply from the server
if( recv(sock , client_message , 2000 , 0) < 0)
{
puts("recv failed");
break;
}
puts(client_message);
}
close(sock);
return 0;
}
Now my problem is why does it suddenly stop when it reaches the 4th connection?
Original Question
I am trying to write my first C client. I needed to create 4 connections to the server from one client to simulate 4 clients connected where each connection of course has its own handler.
Here is what I have so far:
void connect_to_server(struct sockaddr_in server);
int main(int argc , char *argv[])
{
int number_of_connections, x;
struct sockaddr_in server;
server.sin_addr.s_addr = inet_addr("ipaddress");
server.sin_family = AF_INET;
server.sin_port = htons( port );
number_of_connections = 4;
for ( x = 0; x < number_of_connections; x++ ) {
connect_to_server(server);
}
return 0;
}
void connect_to_server(struct sockaddr_in server) {
int sock;
char message[1000] , server_reply[2000];
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1)
{
printf("Could not create socket");
}
puts("Socket created");
if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("connect failed. Error");
}
while(1)
{
scanf("%s" , message);
if( send(sock , message , strlen(message) , 0) < 0)
{
puts("Send failed");
}
if( recv(sock , server_reply , 2000 , 0) < 0)
{
puts("recv failed");
break;
}
puts(server_reply);
}
close(sock);
}
Well I'm obviously also new to C. So what is wrong? Should I declare more sockets like: int sockA, sockB, sockC, sockD or I guess its the while loop inside the connect_to_server?
It seems the new version of the implementation uses multithreading: pthread_create(...) function call. But is there an implementation of waiting after the threads are created?
For example, the waiting can be implemented:
by using pthread_join(...) function call;
by waiting for specific key press event using getchar() function call.
Notes
Please be careful with these statements:
if (send(sock, handshakeBuf, sizeof(handshakeBuf), 0) < 0)
if (recv(sock, client_message, 2000 , 0) < 0)
The send() and recv() functions do not guarantee that the entire buffer will be sent/received after one function call. The functions return the actual number of sent/received bytes.
Please introduce analysis of the returned value for send() and recv() function calls: continue sending if not all bytes are sent, continue receiving if "not enough" bytes are received. Also, there is an article related to the some basics of the network programming: TCP/IP client-server application: exchange with string messages.
Related
I'm trying to implement a multithreaded tcp server with the following code.
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);
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 newsockfd = *(int*)socket_desc;
int read_size;
char *message , buffer[2000];
int n;
struct auth details;
char* reply;
char cmd[100] = {0};
//Receive a message from client
while( (read_size = recv(newsockfd , buffer , 2000 , 0)) > 0 )
{
printf("Incoming data: %s", buffer);
if(parseData(cmd, buffer, "/", "-")) /* If received data is compliant */
{
details = authenticate(cmd);
if (details.verified) // If said user can execute this command.
{
reply = execute(cmd); // Execute.
n = write(newsockfd, reply, strlen(reply));
if (n < 0) { error("ERROR writing to socket"); }
free(reply);
reply = NULL;
}
else // Authentication failed.
{
n = write(newsockfd, details.error_msg, strlen(details.error_msg));
if (n < 0) { error("ERROR writing to socket"); }
else{
if(debug) printf("sent: %s\n", details.error_msg);
}
}
}
}
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;
}
The authenticate function is defined in an implementation file:
struct auth authenticate(const char* const command)
{
struct auth data;
char* db_pwd;
char* perm;
char* username = "testUser";
char query[200] = {0};
data.verified = FALSE;
data.error_msg = "";
printf("in auth\n");
MYSQL_ROW row;
snprintf(query, 200, "SELECT password FROM userlist WHERE user='%s'", username);
if ((row = mysql_fetch_row(run_query(query)))) // if user is on list
{
db_pwd = row[0];
if(!strcmp(db_pwd, password))
{
if (!(strcmp(command, "test")))
{
data.verified = TRUE;
}
}
}
return data;
}
I have a working single threaded version of this program(main) with the same implementation file, the segmentation fault occurs only with the multithreaded version.
Am I doing something wrong in my code?
How should I proceed with debugging?
Any ideas would be appreciated.
Read documentation of MySQL C API, notably ยง 23.8.12 C API Threaded Function Descriptions It internally uses a socket connection to the mysqld server process, so you have to serialize all MySQL functions.
So, define your global mutex, and protect all the functions doing mysql calls with that mutex (from a request to fetching all the rows of the reply). Better yet, design your application so that only one single thread (usually the main one) is using mysql functions.
Compile with all warnings and debug info (gcc -Wall -g). Use the debugger (gdb) and perhaps valgrind
If unfamiliar with mutexes, you might want to read a pthread tutorial
I have two programs for server and client. My server can connect to multiple client. But the problem right now I am facing is that, I want to display some message from the server side to client side but I am unable to do that. Both the server and client program are provided below. I think the syntax that is preventing me to print the message on the client side is scanfwhich is used the code of client (second line of the while loop). I am not getting any solution for that about how to display the two messages from the server side when the client will get connected.
Problem 1:
Server side messages that I want to display on the client side when client gets connected : (can be found in the new_connection_handler function)
message = "This is connection handler\n";
message = "Type something \n";
Problem 2:
Why I need to use the sleep (2) on the client side? If I do not use the sleep (2), then I cannot receive the data sent by the client on the client side. The data shows when I send something second time from the client side.
Problem 3:
Is it possible to write both the client and server code together and compile and run it using command line arguments?
Server Code:
#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;
if( pthread_create( &thread_id , NULL , new_connection_handler , (void*) &client_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;
}
Client Code:
#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];
int len;
//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);
//Send some data
if( send(sock , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
sleep (2);
//Receive a reply from the server
if((len = recv(sock , server_reply , 2000 , 0)) < 0)
{
puts("recv failed");
break;
}
puts("Server reply :");
server_reply [len]='\0';
printf("%s\n", server_reply);
}
close(sock);
return 0;
}
Your frames are out of sync You open your client handling thread with two sends from the server. Without your "sleep", you pick up one, but not the other. your buffer sizes are also not being used correctly, as they're inconsistently being treated as terminated strings when in fact their send length is based on strlen (which is ok, so long as it is consistent).
I think this is what you're trying to do, with a few modifications:
Client Code
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdint.h>
int main(int argc , char *argv[])
{
int sock;
struct sockaddr_in server;
char message[1000] , server_reply[2000];
int len;
//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((len = recv(sock, server_reply, sizeof(server_reply), 0)) > 0)
{
printf("Server reply: %.*s", len, server_reply);
printf("Enter message : ");
if (fgets(message, sizeof(message), stdin) == NULL)
break;
//Send some data
if( send(sock , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
}
close(sock);
return 0;
}
Server Code
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<pthread.h>
#include<stdint.h>
#define MAX_CLIENTS 5
//the thread function
void *new_connection_handler(void *);
int main(int argc , char *argv[])
{
int socket_desc , client_sock;
struct sockaddr_in server , client;
socklen_t c = sizeof(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(client);
while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, &c)) )
{
printf("Connection accepted");
pthread_t thread_id;
if( pthread_create( &thread_id , NULL , new_connection_handler , (void*) (intptr_t)client_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 = (intptr_t)socket_desc;
int read_size = 0;
char client_message[2000];
static const char rdy[] = "READY\n";
write(sock, rdy, sizeof(rdy)-1);
//Receive a message from client
while( (read_size = recv(sock , client_message , sizeof(client_message) , 0)) > 0 )
write(sock , client_message , read_size);
if(read_size == 0)
{
printf("Client disconnected\n");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
return 0;
}
This still needs better join-logic on the client threads, but if you paste and compile each with appropriate flags I think it does what you're trying to achieve.
Best of luck.
Below is my socket client program. I am trying to send some data from client and trying to receive it in the client side. When I run the program, there is no compilation error. But I am unable to receive the sent message correctly in the client side. I think I am doing some error in
server_reply [len]='\0';
printf("%s\n", server_reply);
My original code is written below: (you can find my server program here in this link Multiple client not getting connected and cannot communicate at the same time)
#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];
int len;
//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);
//Send some data
if( send(sock , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
//Receive a reply from the server
if(len = (recv(sock , server_reply , 2000 , 0)) < 0)
{
puts("recv failed");
break;
}
puts("Server reply :");
server_reply [len]='\0';
printf("%s\n", server_reply);
}
close(sock);
return 0;
}
This line is wrong.
if (len = (recv(sock , server_reply , 2000 , 0)) < 0)
{
puts("recv failed");
break;
}
Should be:
if ((len = recv(sock , server_reply , 2000 , 0)) < 0)
{
puts("recv failed");
break;
}
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.
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.