I can't understand the result of this chatting program - c

So I made a simple server-client program that can communicate with each other using fifo file (msgfifo).
My question is: When I type a message which includes a space, the receiver process runs several times with number of words.
That's not I expected, as I expected to print it out as a whole sentence, but it doesn't, and I want to know why.
When I type a something to send, process send SIGUSR1 signal to another.
/* receive msg part */
/* added this using sigset(SIGUSR1, receiveSIGUSR1) */
void receiveSIGUSR1()
{
char* msg = "\nIncoming Message from client...";
char* msg2 = "\nClient : ";
char buf[max_of_msg];
int fd;
write(1, msg, strlen(msg)+1);
fflush(stdin);
if( (fd = open("./msgpipe", O_RDONLY)) < 0)
{ perror("open"); exit(1); }
read(fd, buf, max_of_msg);
close(fd);
write(1, msg2, strlen(msg2)+1);
write(1, buf, strlen(buf)+1);
flag = 0;
}
/*send msg part*/
while(1)
{
flag = -1;
printf("\nType what u want to send : ");
scanf(" %s", msg);
if(flag == 0) continue;
printf("msgtaken\n");
fflush(stdin);
if( (fd = open("./msgpipe", O_RDWR)) < 0)
{ perror("exit"); exit(1); }
kill(clpid, 30);
sleep(2);
printf("Send message to Client..\n");
write(fd, msg, max_of_msg);
printf("Message Sent...\n");
}
Expected:
Client : Hello Server this is client
Actual:
/* server */
Incoming Message from client... Hello Incoming Message
from client... this Incoming Message from client... is
Incoming Message from client... client Type what u
want to send :
/client/
Type what u want to send : Hello Server This is client
msgtaken Send message to server.. Message sent
Type what u want to send : msgtaken Send message to server..
Message sent Type what u want to send : msgtaken Send
message to server.. Message sent Type what u want to send
: msgtaken Send message to server.. Message sent Type
what u want to send : msgtaken Send message to server..
Message sent
Type what u want to send :

That's because this is how it takes input:
scanf(" %s", msg);
Let's have a look at the documentation of scanf (emphasis mine):
s: Any number of non-whitespace characters, stopping at the first
whitespace character found. A terminating null character is
automatically added at the end of the stored sequence.
That's why it stops after Hello when you send Hello Server this is client. Also note the space in " %s", this means that it will also ignore any whitespace at the start of the input. So when it reads the Server on the next run through the loop, this makes it ignore the space between Hello and Server. As a result, it goes through the loop five times, and the messages each time are Hello, Server, this, is and client.
Instead, you could use getline:
char *message = NULL;
size_t length;
getline(&message, &length, stdin);
// use message
free(message);
A little side note: to make your scanf call more safe, you can specify a maximum size for the string input:
scanf(" %99s", msg);
Per example, this would mean that only 99 char can be read in, plus a null terminator, for a buffer size of 100. This way you can avoid undefined behavior that would occur if the user would enter a string that is too big for your buffer.

Related

C : String comparing

bool done;
done = false;
while (!done) {
/* read the message */
bzero(msg, 100);
printf("[client]Type something: ");
fflush(stdout);
read(0, msg, 100);
if (strcmp(msg, "/done") == 0) {
done = true;
/* sending the message to the server */
if (write(sd, msg, 100) <= 0) {
perror("[client]Error sending the message to the server.\n");
return errno;
}
} else {
/* sending the message to the server */
if (write(sd, msg, 100) <= 0) {
perror("[client]Error sending the message to the server.\n");
return errno;
/* reading the answer given by the server*/
if (read(sd, msg, 100) < 0) {
perror("[client]read() error from server.\n");
return errno;
}
/* printing the received message */
printf("[client]The received message is: %s\n", msg);
}
}
Here's the code that i have problem with. So i want to send messages to the server until I send the message "/done", the code works, I send messages continuously but even when i type and send "/done" the process doesn't end.
I think there's a problem with the bzero function that "clears" the msg or maybe i don't understand it so good.
I also tried to wrote my own function to check if two strings are the same, but no effect also.
So how should i write the condition or "clear" the msg so i can send messages continuously and after i send "/done" the execution ends?
P.S. the msg is declared earlier in the code as char msg[100];
When you read from 0, you're reading from stdin. If that is a terminal that you are typing into (you don't say), you likely have it set up in normal (canonical) mode, so you'll read a line, which probably includes a newline (\n) character. So when you enter /done, the string you get in your msg buffer is "/done\n" which doesn't match "/done"...
read(2) is including the '\n' at the end of the string. When you use low-level read you get everything. When trying to debug strings, it can be helpful to put quotes in your print statement, like
printf("[client]The received message is: '%s'\n", msg);
as this immediately shows invisible whitespace.
TCP is not a message protocol. It does not glue bytes together into messages. If you want to use TCP to send and receive messages, you'll need to implement functions that send and receive messages.
I must strongly caution you not to fail into the trap of thinking that changing your code from happening not to work when you tried it to happening to work when you try it means that you've fixed it. Your code fails if read returns 1. You need to implement a sensible function to receive a message or your code will only be working by luck, and I can tell you from painful experience that one day your luck will run out.

Multiclient server socket doesn't print the client messages

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.

C: send/recv partial packet at first connection and receives the rest at second connection

Code for client:
/* Packet struct */
struct
{
int x;
int y;
char mess [5];
} Packet;
/* Assigning values to packet */
Packet.x = 5;
Packet.y = 25;
strcpy(Packet.mess, "Hell");
/* Send packet */
int bytesTransmitted = send(socketID, &Packet, sizeof(Packet), 0);
/* Check transmission */
if (bytesTransmitted < 0)
{
printf("Error sending message!\n");
return 1;
}
else
{
printf("Message sent successfully! Message size: %lu, bytes trasnmitted: %d", sizeof(message), bytesTransmitted);
}
/* End of pogram */
return 0;
Code for server:
struct
{
int x;
int y;
char mess [5];
} Packet;
unsigned int clientLength = sizeof(clientAddress);
/* Main loop */
while (1)
{
int listenSocket = accept(socketID, (struct sockaddr*)&clientAddress, &clientLength);
if (listenSocket > 0) /* Connection accepted */
{
printf("Received connection from: %s:%d\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port));
if (recv(listenSocket, &Packet, sizeof(Packet), 0) > 0)
{
printf("Message: %s\n x:%d\n y:%d", Packet.mess, Packet.x, Packet.y);
/* HERE IS THE PROBLEM */
}
}
}
Output from server at first connection:
Received connection from: 127.0.0.1:48648
Message: Hell
x:5
y is missing.
I terminate the client and restart it without touching the server.
Output from server:
y:25 <-- *y* from ?previous? connection
Received connection from: 127.0.0.1:49368
Message: Hell
x:5 <-- *x* from current connection
y is missing again.
Any help or suggestions are greatly appreciated!
TCP is a stream oriented protocol. There are no "packets" at the level you are writing code. TCP guarantees that the same bytes you send, will arrive at the destination in the same order. However, there are no message boundaries.
Your code that calls recv() must be prepared to receive fewer bytes than requested, and call recv() again until you get the number of bytes you expect.
Your issue has nothing to do with TCP streaming (though you do have that problem and should fix it per Greg's answer).
Instead, your issue is output buffering -- by default stdout is line buffered, which means that characters written with printf actually go into a buffer and are only output to the screen when a \n (newline) is written to the buffer. So your line:
printf("Message: %s\n x:%d\n y:%d", ...
Will only print up to the last newline (before y), and the y:25 will just be put in the buffer. Later, when you print more stuff that includes a newline, the buffered string will appear along with whatever else you printed. Add a newline after the "y:%d" and it will appear when you expect.
You have two problems:
your server code doesn't have a newline at the end of the second printf, so the output can't be what you show. Either append a newline to that second printf, or use fflush(stdout) after it, to flush the value of y.
as Greg says, you can't rely on receiving entire messages anyway, and should have a loop here.
I'd expect #1 to be your current problem, but you should fix both.

Truncated Buffer

I'm trying to troubleshoot a strange C programming problem.
I'm entering a URL on a client program and then transferring that URL to a server program. The only issue is, that when the server program receives the URL it's missing it's first two characters. So, if the url is http://www.google.com what the server reports is receiving is "tp://www.google.com."
The weird thing is that it's not some partial send problem. I'm checking on the number of bytes sent and it's claiming that the entire message is sent. The issue is that on the receiving end it's only claiming that it's getting a small chunk of the data. The receiver reports back that it's received the message length -2. Here is the code on the receiving end:
printf("%s \n", "Connected. Receive length of URL to wget.");
if ((messageSize = recv(acceptDescriptor, &urlLength, sizeof (int), 0)) == -1) {
perror("recv URL length");
exit(1);
}
urlSizeInt = atoi(urlLength);
char url[urlSizeInt];
printf("%s %d \n", "urlSizeInt: ", urlSizeInt);
printf("%s \n", "Receive URL to wget.");
if((messageSize = recv(acceptDescriptor, &url, 13, 0)) == -1) {
perror("recv URL");
exit(1);
}
Sending code:
printf("%s \n", "Connected");
//connected to first stepping stone in the chain.
//transfer the length of the URL
if (send(socketDescriptor, urlLengthStr, strlen(urlLengthStr), 0) == -1){
perror("send URL Length");
exit(0);
}
//transfer the URL
printf("%s %d \n", "strenlen(url): ",strlen(url));
printf("%s %s \n", "url: ",url);
int sent;
int totalSent=0;
if((sent=send(socketDescriptor, url, strlen(url), 0))==-1){
perror("send URL");
exit(0);
}
printf("%s %d \n", "sent: ",sent);
Send Output:
Connected
strenlen(url): 13
url: http://www.cs
sent: 13
Receive Output:
Connected. Receive length of URL to wget.
urlSizeInt: 13
Receive URL to wget.
messageSize: 11
URL Received: tp://www.cs
Code to encode the length as a char for sending:
char* url = "http://www.cs";
int urlLength = strlen(url);
char* urlLengthStr;
sprintf(urlLengthStr, "%d", urlLength);
Thanks for posting the full code. the problem lies in the way you send the UrlLength. Because you always recv sizeof(int) bytes, your first read is consuming the first bytes of the sent URL.
Start from the beginning - assume you don't send the URL Length.
Problem : URLs are variable length. How can the receiver know when it's read it all?
Solution : Send the length before
This is fine, unless you encode the length as a string, because that introduces another problem
Problem : The URL length may be variable length ("1", "12","1234"). How can the receiver know when it's read it all?
Solution : Haven't we been here before somewhere...
There are a couple of ways out of this recursive problem:
Solution a : Encode the URL length as a fixed size field. (you can just send the binary representation of an int, although beware of byte ordering problems - or you could encode it as a fixed-width ascii field , e.g, "00000124"
TX (ignoring byte ordering issues mentioned by JimR)
int urlLength = strlen(url);
send(socketDescriptor, &urlLength, sizeof(int), 0)
RX:
int urlLength;
recv(socketDescriptor, &urlLength, sizeof(int), 0)
Solution b: Use a termination character (often null, or linefeed) to indicate the end of the URL. Just read bytes in a loop until the terminator is reached. This also solves the 'partial recv' problem you would otherwise encounter.
When you're reading from a socket, you're reading a stream, not a file.
See here for good guidelines for writing network code.
Even though the sending side may have sent all the data at once, that does not guarantee that you will see all the data at once. You have to loop on recv, taking into account the number of bytes received for each call. If recv returns 0 the socket was closed or there was an error and you will receive no more data from that socket.
With those things in mind... Kinda sorta pseudo code, I didn't test this, but hope it gives you the idea:
int expectedLength = readLengthFromSocket( socket, sizeof( int ) );
int bytesRead = 0;
char buffer[expectedLength];
bytesRead = recv( socket, buffer, ... );
runningLength = 0;
if( bytesRead < 1 )
// Socket closed or there was an error, handle that here
else
{ runningLength += bytesRead;
while( runningLength < expectedLength )
{
bytesRead = recv( socket, buffer + runningLength, ... );
if( bytesRead < 1 )
// Socket closed or there was an error, handle that here
break;
else
runningLength += bytesRead;
}
}
Note that reading and writing int, long, long long, short and the unsigned variants over the network typically require byte swapping. Reading a buffer of bytes does not.
See here for an explanation.

Sending and receive two strings in C Socket

This is the client side where it prompts user to enter a string and send it to the server
//send
printf("\nPlaintext : ");
gets(send_data);
send(sock,send_data,strlen(send_data), 0);
//recv
bytes_recieved = recv(sock, recv_data, 1024, 0);
recv_data[bytes_recieved] = '\0';
printf("\nEnciphered text = %s " , recv_data);
fflush(stdout);
close(sock);
And this is the server side.
sin_size = sizeof(struct sockaddr_in);
//accept
connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);
printf("\n I got a connection from (%s , %d)", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
//recv
bytes_recieved = recv(connected, recv_data, 1024,0);
recv_data[bytes_recieved] = '\0';
printf("\n RECIEVED DATA = %s " , recv_data);
cod = encipher(recv_data, key, 1); //printf("Code: %s\n", cod);
dec = encipher(cod, key, 0); //printf("Back: %s\n", dec);
//send
send(connected, cod, strlen(cod), 0);
send(connected, dec, strlen(dec), 0);
So the thing is, I want to send two strings named 'plaintext' and 'key' from the client. At the server side, I expected it to receive the two strings and process it under encipher() function and then send it back to the client.
How do I send two strings from a client and receive two strings from the server?
I would send the string first then get the server to write back some confirmation to the client that it received it. Then the client can send the key, the server can do what it needs to and return the message to the client. If you keep the socket connection open you can continue to send and receive information from/to either end of the connection with send() and recv(). There are a number of ways depending on the structure of your strings. You could use a delimiter in the data you send to the server to indicate the end of the string, so that the portion that remains is your key - this would allow the server to receive the data in one packet and reply in one packet. I am not sure there is a right way to do it - you must decide based on the needs of your application. Either way, you should check the return values of the socket functions to check that you are getting and sending what you think you are.
send a 16bit short containing the size of the 1st string, then the 1st string, then another short containing the size of the 2nd string then the 2nd string. On the server, read a 16bit int then read that many bytes, then do the same for the 2nd string.

Resources