I'm trying to implement a client-server application with multiclients using threads. Just to try, I would like to print the messages from each client, but when I send messages from a client, the server does not print anything.
Server (thread code)
void comunicationHandler(void *socket)
{
int sock = *(int*) socket;
char msg[2000];
while ((strcmp(msg, "!quit")) != 0) {
if (recv(sock, msg, 2000, 0) < 0)
puts("Error recv");
printf("%s", msg);
}
puts("Client Disconnected\n");
}
when I send "!quit", the Server goes in a infinite loop printing the messages
Client
for(;;) {
printf("\nInserisci il msg: ");
scanf("%s", msg);
if (strcmp(msg, "!quit") == 0)
break;
write(sd, msg, 2000);
}
There are multiple problems with your code:
TCP is stream based, there is no guarantee that all the bytes you send will be received in one shot on the other side. You need to modify code to check what is the number of bytes received and is it atleast equal to the size of "!quit" before you go in for the "strcmp" comparison.
Better to null terminate the buffer once you receive the buffer equal to the size of "!quit"
It is not clear as to why you are sending a 2000 bytes buffer from the client when you intend to send only "!quit". Modify and send only appropriate size as needed
Check recv return value against 0 also
Break out of the loop in both server and client once the Job is done.
Server goes in a infinite loop
You want to test recv()'s result against 0 and quit in this case. 0 indicates that the client orderly closed the connection.
Related
There are a couple of things that I'm struggling with here.
The first is how to send a string via C stream sockets when you can't guarantee that the string will be sent/received in one go because it's larger than the BUFSIZs or for some other reason. I imagine that this needs to be done with some sort of infinite loop that you break out of, but I can't figure out how to do this.
The second is I need to do this without breaking the connection. I know that in a lot of implementations infinite loops are broken by the message sender closing the connection, which results in a recv status of 0. The recipient can then use this to break out of their loop. But is there a way of completing the transfer without breaking the connection?
EDIT: As I understand from the comments, I need to do something like the following, but this produces errors:
CLIENT CODE
char message[a_large_number];
snprintf(message, a_large_number, "%s", "a_very_long_string...");
int BUFSIZ = a_small_number;
// establish socket connection
while (1) {
int sent = send(networkSocket, message, sizeof(message), 0);
if (sent == (sizeof(message))) {
break;
}
}
// do something else
//close(socket_connection)
SERVER CODE
int BUFSIZ = another_small_number;
char client_message[];
// establish socket connection
while (1) {
char buffer[BUFSIZ];
int received = recv(clientSocket, buffer, sizeof(buffer), 0);
if (received == 0) {
break;
}
strcat(client_message, buffer);
memset(buffer, 0, sizeof(buffer));
}
// do something else
// close(socket_connection)
I have a small c program which continually accepts data from one server and then translates it and sends it to a second server. The second server (basically a terminal app) then sends back the command prompt characters. When I send data to the second server it works as expected. If I do not read the data returned from the second server, then the second time I send data it never receives the data even though my program sends it and does not generate any errors. If I read the data returned by the second server it works as expected.
Can anyone explain this behavior? I am just curious as to what is going on. Both my process and the remote processes are continually running.
int sendCCL_TCP(unsigned char *buf, struct sockaddr_in *ccladdr){
int n,outfd;
if ((outfd = socket(AF_INET, SOCK_STREAM, 0)) <0) {
fprintf(errorfd,"ERROR creating output socket to send CCL\n");
fclose(errorfd);
return(FALSE);
}
if (connect(outfd, (struct sockaddr *)ccladdr, sizeof(*ccladdr)) < 0) {
fprintf(errorfd,"ERROR connecting to CCL server (%i) %s \n",errno,strerror(errno));
fflush(errorfd);
}
else{
n = write(outfd, buf, strlen(buf));
if (n < 0) {
fprintf(errorfd,"ERROR writing to CCL server (%i) %s\n",errno,strerror(errno));
fflush(errorfd);
}
write(outfd,"\r",1);
//If I comment out the following, the remote server does not
//receive the data the second and subsequent times
n=read(outfd,buf,9);
}
close(outfd);
return(TRUE);
}
How to keep the connection listening from the connected client? In the below code the thread receives the data and replies to the client and disconnects. I want to put the receive and sent process in loop. How can I do that ?
void *thread_handle_connection(void *arg) {
char buffer[MAX_MSG_SIZE]; // Receive buffer
int bytes_read;
do {
// If there aren't any connections, sleep and recheck every second
while(!num_connections && !term_requested) {
sleep(1);
}
// Lock out connections queue and grab the first one
pthread_mutex_lock(&queue_mutex);
int connectionfd = remove_connection_from_queue();
pthread_mutex_unlock(&queue_mutex);
if(-1 == connectionfd) {
continue;
}
// pthread_barrier_wait(&barrier); // Barrier for threads - for testing only
// Read up to 1024 bytes from the client
bytes_read = recv(connectionfd, buffer, MAX_MSG_SIZE - 1, 0);
// If the data was read successfully
if(bytes_read > 0) {
// Add a terminating NULL character and print the message received
buffer[bytes_read] = '\0';
// Calculate response
int multiplicand = atoi(buffer);
char *response;
asprintf(&response, "%d", multiplicand * MULTIPLIER);
// Echo the data back to the client; exit loop if we're unable to send
if(-1 == send(connectionfd, response, strlen(response), 0)) {
warn("Unable to send data to client");
break;
}
free(response);
}
// Close connection
close(connectionfd);
} while(bytes_read > 0 && !term_requested);
return NULL;
}
First, recv function doesn't guarantee that you read everything that has been written by sender. You may get part of the data (for example sender may send 10KByte but receiver may receive only 1.5K on first read).
Second, send function doesn't guarantee that it send everything you ask. If not everything has been sent you need to send rest of the answer.
Third, TCP is stream oriented. This means that you need to separate one message from another. For text-based protocol typically "new line" is used for this purpose.
Putting all together. If you want persistent connection with request you need:
define request and response separators
maintain read buffer
read all data to the buffer and scan it for request separator
send response with response separator
If you want level up in networking programming you may want to know something about non-blocking operations and poll/select functions.
I'm learning to work with sockets in c.
Here is my code:
void work_with_client(int client_sock){
char buff[10] = {0};
while(1){
kv_log_message("\tWork with client\n");
int is_received = recv(client_sock, buff, 10, 0);
if(is_received < 0){
perror("Received failed");
} else {
printf("RESPONSE: %s\n", buff);
}
printf("RESPONSE %d\n", is_received);
sleep(1);
}
}
When I connect through telnet to this server and immediately disconnect, server print this lines:
Work with client
RESPONSE:
RESPONSE 10
Work with client
RESPONSE:
RESPONSE 10
Work with client
RESPONSE:
RESPONSE 10
Work with client
RESPONSE:
RESPONSE 10
Work with client
RESPONSE:
RESPONSE 1
Work with client
RESPONSE:
RESPONSE 0
Work with client
And I don't get why first 4 recv calls get full size of buffer data (I don't write anything to the socket from client perspective).
Any suggestions?
P.S. Run on Mac OS X Yosemite
UPDATE: i test my program on Linux, and recv call always return 0 in my case, so probably the problem in telnet on Mac OS X
When recv() returned 0 this indicates the other side shut down the connection.
From man recv:
RETURN VALUE
[...] The return value will be 0 when the peer has performed an orderly shutdown.
You then might like to exit the while() loop.
Update:
Also the code might invoke undefined behaviour by passing a non 0-terminated "string" to printf().
To fix this read one char less to buff then it's size and add the 0-terminator.
while (1)
{
ssize_t is_received = recv(client_sock, buff, sizeof buff - 1, 0);
if (is_received < 0){
perror("Received failed");
break;
} else if (is_received == 0) {
printf("%s\n", "peer shutdown");
break;
}
buff[is_received] = '\0';
printf("RESPONSE: %s\n", buff);
}
Ok i get it, telnet on Mac OS X (Yosemite) send some data if you just close terminal without proper closing connection through telnet itself (i.e. put escape character and quit command).
Honestly I don't know is it bug or some kind of debug behaviour.
My server is sending packets to the client, but the second packet is not shown.
I don't know why this is happening if my socket is of blocking type.
while(1){
memset(buf,0,1024);
numbytes=0;
if ((numbytes = recv(sockfd, buf, 1024, 0)) == -1) {
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
printf("%s\n",buf);
fflush(stdout);
}
fclose(fp);
close(sockfd);
That could be happening because your sever is sending an empty string. So your client does not block because it received the '\0' character and it does not print anything because it is an empty string.
The second reason could be because your server closed the connection. In this case the value of numbytes is zero, and your client will not print anything because you also end up with an empty string in your buffer.
One issue with your code is that if the server sends 1024 bytes or more,numbytes is goign to be equal to 1024 and the expression buf[numbytes] will cause a segmentation fault if your buffer size is also equal to 1024. You could prevent this problem by receiving 1023 instead of 1024.