I have just started learning socket programming.
Currently the server and the client are on the same workstation and everything seems to work. The server is running in c programming and my client is an android program. I managed to have a one way connection, sending data from client to server. I would like to send some string back to client.
Please advice me.
void *connection_handler(void *);
int main(int argc , char *argv[])
{
int socket_desc , client_sock , c;
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( 7800 );
//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);
pthread_t thread_id;
while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
{
puts("Connection accepted");
if( pthread_create( &thread_id , NULL , connection_handler , (void*) &client_sock) < 0)
{
perror("could not create thread");
return 1;
}
//Now join the thread , so that we dont terminate before the thread
//pthread_join( thread_id , 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 )
{
//end of string marker
client_message[read_size] = '\0';
printf("%s\n", client_message);
//Send the message back to client
write(sock , client_message , strlen(client_message));
//clear the message buffer
memset(client_message, 0, 2000);
}
if(read_size == 0)
{
//puts("Client disconnected");
//fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
return 0;
}
There are different ways to transmit data to another socket and it doesn't matter if it's either a server or a client.
write
As you did in your code, you can use the system call:
ssize_t write(int fd, const void *buf, size_t count);
It writes from the buf to the file related to the file descriptor fd. The return value will tell you if the message was sent correctly.
send, sendto, sendmsg
This is the second way you can send data to a socket. The only difference between write and send is the argument flags:
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
but if you set flag to 0, write and send will work in the same way.
sendto and sendmsg are quite different from send because they have more arguments. You can get all information from man pages available online or in Linux.
http://man7.org/linux/man-pages/man2/send.2.html
while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
is wrong; you probably want to check >= 0 or (even better) express this in another way.
The lone
write(sock , message , strlen(message));
is not good:
you should check the error code
it will be very difficult for the receiver to split the result.
write() will kill your program with SIGPIPE when the other end has been closed
I suggest something like
bool send_data(int fd, void const *data, size_t len)
{
while (len > 0) {
ssize_t l = send(fd, data, len, MSG_NOSIGNAL);
if (l > 0) {
data += l;
len -= l;
} else if (l == 0) {
fprintf(stderr, "this is ugly and can not happen...\n");
break;
} else if (errno == EINTR) {
continue;
} else {
perror("send()");
break;
}
}
return len == 0;
}
and for string datatypes
bool send_string(int fd, char const *str)
{
size_t l = strlen(str);
uint32_t l_be = htobe32(l);
if ((uint32_t)(l) != l)
return false;
return (send_data(fd, &l_be, sizeof l_be) &&
send_data(fd, str, l));
}
For receiving, you can implement recv_data() similarly to send_data() above. Depending on your memory allocation strategy, you can implement either
bool recv_string(int fd, char *str, size_t max_len, size_t *len)
{
uint32_t l_be;
size_t l;
if (!recv_data(fd, &l_be, sizeof l_be))
return false;
l = be32toh(l_be);
if (l >= max_len)
return false;
if (!recv_data(fd, str, l))
return false;
str[l] = '\0';
if (len)
*len = l;
return true;
}
or write something which malloc() memory for the received data after reading the length.
Now, you can do on one side:
if (!send_string(fd, "foo") ||
!send_string(fd, "bar") ||
!recv_string(fd, resp, sizeof resp, NULL))
error();
and on the other one
if (!recv_string(fd, req0, sizeof req0, NULL) ||
!recv_string(fd, req1, sizeof req1, NULL) ||
!send_string(fd, handle_request(req0, req1)))
error();
Related
Im writing a program which connects to a browser and sends the http request from the browser to a server, and then sends the response back to the browser, which loads the page with some of the content. My program sends things successfully and loads pages, but does not run continuously and will crash after a random amount of time- sometimes 10 seconds of running sometimes 1 minute. I want this proxy to be able to run forever. Below is how I have structured my code. I have included the recv and write section which I think is causing my errors in full. I am pretty new to socket programming and c In general and looking for some tips on my structure and anything I may have missed.
int main(int argc, char *argv[])
{
char ip[40]
char *host = argv[1];
char *port_s = argv[2];
int err;
int socket_browser, socket_newBrowser, c;
struct sockaddr_in server, client;
int n;
socket_browser= socket(AF_INET, SOCK_STREAM, 0);
if (socket_browser < 0)
{
printf("Could not create socket");
}
if (err = bind(socket_browser , (struct sockaddr *)&server, sizeof(server)) != 0)
{
resourceError(err, "bind");
return 1;
}
if (err = listen(socket_browser , 3) != 0)
{
resourceError(err, "listen");
}
while (1){
c = sizeof(struct sockaddr_in);
server_socket= accept(socket_browser, (struct sockaddr *)&client, (socklen_t *)&c);
char buf[256];
int n;
n = recv(socket_newBrowser, buf, 256, 0);
if (n < 0){
resourceError(n,"recv");
}
int server_socket;
struct sockaddr_in server2;
server_socket= socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0)
{
resourceError(server_socket, "serverSocket");
}
server2.sin_addr.s_addr = inet_addr(ip);
server2.sin_family = AF_INET;
server2.sin_port = htons(80);
connect(server_socket, (struct sockaddr *)&server2, sizeof(server2))
send(server_socket, buf, strlen(buf), 0);
char reply[256];
int bytes_reply = 0;
do
{
bytes_reply = recv(server_socket, reply, sizeof(reply), 0);
// Need to check for double enter as this currently does not work in telnet
if (bytes_reply == -1)
{
perror("Recv error");
}
else
{
write(server_socket, reply, bytes_reply);
}
} while (bytes_reply > 0);
printf("connections closed");
}
return 0;
}
I think your problem (or at least a problem) is:
n = recv(socket_newBrowser, buf, 256, 0);
/*versus*/
send(server_socket, buf, strlen(buf), 0);
buf is not null-terminated, you should have used the n value returned from recv instead of strlen.
I have some problems with my Server/Client.
If multiple people connect to my server, and one of them quit the connection to the server, all other, which are also connected to the server, lose their connection to.
void *connection_handler(void *);
extern int check_err_buffer(int sock);
extern error_t *error_buffer;
extern invalid_user_input_t invalid_user_input;
regex_t regex;
int main(int argc, char *argv[]) {
//init KVS
init();
int socket_desc, client_sock, c, *new_sock;
struct sockaddr_in server, client;
//Create socket
socket_desc = socket(AF_INET, SOCK_STREAM | O_NONBLOCK, 0);
int opts;
opts = fcntl(socket_desc,F_GETFL);
opts = opts & (~O_NONBLOCK);
fcntl(socket_desc,F_SETFL,opts);
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(8503);
//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 (1) {
puts("waiting for client...");
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;
pthread_create(&sniffer_thread, NULL, connection_handler, (void *) new_sock);
//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;
}
In the main function I accept the different connection from the clients.
I have more functions, which I didn't put in, because they are not so relevant for this problem.
In the second part I will handle some cases. I look if the client type the letter 'q', if it's true, I will close the connection with close().
But in all cases, it close the server, and all connections are lost.
/*
* This will handle connection for each client
* */
void *connection_handler(void *socket_desc) {
//Get the socket descriptor
int sock = *(int *) socket_desc;
char *message, client_message[3000];
puts("sending welcome msg to client...");
write(sock, message, 3000);
int reti;
//compile a regexp that checks for valid user input
regcomp(®ex, "([dg] [0-9]+)|([v] .+)|(p [0-9]+ .+)|q", REG_EXTENDED);
//Receive a message from client
char *input[3];
while(1){
//wait for some client input
recv(sock, client_message, 2000, 0);
//check the input with the regexp
reti = regexec(®ex, client_message, 0, NULL, REG_EXTENDED);
if (!reti) {
//tokenize the client input with \n as a delim char
char *token = strtok(client_message, " ");
int i = 0;
while (token) {
input[i] = token;
token = strtok(NULL, " ");
i++;
}
//quit operation
if (strcmp(input[0], "q") == 0) {
//if a client quits, the server dies. TODO: fix
puts("quitting");
//free(socket_desc);
close(socket_desc);
return 0;
}
//user input does not match regexp, try again..
} else if (reti == REG_NOMATCH) {
error_buffer = invalid_user_input;
check_err_buffer(sock);
usleep(100);
write(sock, " ", 2);
}
}
//Free the socket pointer
free(socket_desc);
return 0;
}
On the client side i test if message[0] == 'q' and I close the socket.
I would be very happy if i will get some help or hints to solve this problem. Thank you
As here
new_sock = malloc(1);
the code allocates 1 byte only, this following line
*new_sock = client_sock;
writes to invalid memory, as an int is assigned, and sizeof int bytes are written to where new_sock points. By definition sizeof int is at least 2, probably more, With this undefined behaviour is invoked. Anything may happen from then on.
To fix this do
new_sock = malloc(sizeof *new_sock);
instead.
Inspecting the return value of functions is debugging for free. close(socket_desc); is nonsense and definitely would return -1 and set errno to EBADFD.
Replace
close(socket_desc);
by
if (-1 == close(socket_desc))
{
perror("close() falied");
}
to see how the code as it stand fails.
I am sending data over to my server which writes the received data back to the client and the data also gets stored in a text file on the server.
I have this problem: if the length of the sent message is smaller than previously sent messages, the extra characters get added to the current message.
For example if I send "hello" first and then I send "all", the stored messages on the file are:
hello
alllo
Here is my 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*)&$
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
puts("Connection accepted");
//Receive a message from client
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));
//append the received data at the end of the file
FILE *f = fopen("data.txt", "a");
if (f == NULL){
printf("Error opening file!\n");
exit(1);
}
char *text = client_message;
fprintf(f, "%s\n", text);
fclose(f);
//clear socket
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
return 0;
}
So I think I need to clear the buffer after writing to the file, but I'm not sure how to do this. I would greatly appreciate your help!
Usual problem. Incorrect copy loop. Ignoring the receive length, and assuming the data fills the buffer and/or is null-terminated.
It should look like this in general:
while ((count = recv(source_sd, buffer, sizeof buffer, 0)) > 0)
{
write(target_fd, buffer, count);
// or
fwrite(buffer, 1, count, target_file);
}
And opening and closing a file every time around the loop is pretty poor.
Nothing to do with clearing the socket buffer. It is clear after the loop.
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.
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