I am sending a file through TCP, and have the server sending a message containing "END_OF_MESSAGE" to alert the client that they have received the whole file and can close the socket. The file is being sent, and the client receives the "END_OF_MESSAGE" string, however, when I use strcmp to compare the received information to "END_OF_MESSAGE", it never says that they match. I have tried strncmp and memcmp but am confused as to why strcmp does not tell me the strings match.
Code snippets:
Server:
char endMessage[MESSAGESIZE] = "END_OF_MESSAGE";
if ((send(clntSocket, endMessage, sizeof endMessage, 0))!= sizeof endMessage) DieWithError("Sending failed");
The above code snippet does get sent.
Client:
if ((bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE - 1, 0)) <= 0)
DieWithError("recv() failed or connection closed prematurely");
totalBytesRcvd += bytesRcvd; /* Keep tally of total bytes */
echoBuffer[bytesRcvd] = '\0'; /* Terminate the string! */
if (!(strcmp(echoBuffer, "END_OF_MESSAGE")==0)){
printf(echoBuffer); /* Print the echo buffer */
printf("\n");
}else{
break; //break out of while loop
}
the strcmp of the echoBuffer and "END_OF_MESSAGE" never returns 0, even though "END_OF_MESSAGE" is what I am sending from the server..I have tried strncmp to compare the first 3 characters ("END") to no avail.
Note: when I print out the echoBuffer, the very last one does print out END_OF_MESSAGE which is just adding to my confusion.
Does anyone have any insights into what I am doing wrong?
Thank you.
am sending a file through TCP, and have the server sending a message containing "END_OF_MESSAGE" to alert the client that they have received the whole file and can close the socket.
Why? Just close the socket. That will tell the client exactly the same thing..
What you're attempting is fraught with difficulty. What happens if the file contains END_OF_MESSAGE? You're going to need an escape convention, and an escape for the escape, and inspect all the data when both sending and receiving.
The actual problem that you're seeing is that END_OF_MESSAGE can arrive along with the last bit of the file, so it isn't at the start of the buffer.
But it's all pointless. Just close the socket.
Related
I am trying to learn client server model in Linux and I have setup two C files namely server.c and client.c. These are the code snippets that I seem to have problems with.
server.c code snippet
char* message = "<query>\n";
write(client_socket_filedescriptor, message, sizeof(message));
client.c code snippet
char* message = "<query>\n";
read(socket_filedescriptor, buffer, sizeof(buffer));
printf("%s", buffer);
printf("\n\n");
printf("%s", message);
Now when I run my server and then when I run my client, I expect the printf statements to print the same strings that is <query>\n, but I keep getting different outputs for buffer and message variables.
The output looks a bit like this when I run client code.
Output image
As you see, these two strings are different. I am trying to simulate a typical TCP handshake and I want to make sure that these two strings are same and then client will start writing or doing something with that server. But I am having this trivial problem. Could anyone tell my how to resolve it? I plan to use strcmp to compare buffer and message variables, but as it stands now, strcmp doesn't return 0 since these are different strings afterall.
You are ignoring the count returned by read(). It can be -1, indicating an error, or zero, indicating end of stream, or a positive number, indicating how many bytes were received. You cannot assume that read() fills the buffer, or that a single send() or write() corresponds to a single recv() or read().
In detail:
write(client_socket_filedescriptor, message, sizeof(message));
You are only sending four bytes, the size of the pointer. And you're ignoring the return value. It should be
int count = write(client_socket_filedescriptor, message, strlen(message));
if (count == -1)
perror("write"); // or better
char* message = "<query>\n";
read(socket_filedescriptor, buffer, sizeof(buffer));
That should be
int count = read(socket_filedescriptor, buffer, sizeof(buffer));
if (count == -1)
perror("read"); // or better
else if (count == 0)
; // end of stream: the peer has disconnected: close the socket and stop reading
else
Back to your code:
printf("%s", buffer);
That should be
printf("%.*s", count, buffer);
I plan to use strcmp()
You should plan to use strncmp(), with count above as the length parameter. In any case you can't assume the input ends with a null unless you (a) ensure you send the null, which you aren't, and (b) write a read loop that stops when you've read it.
I am working on an program for school and having some issues with sockets. I have pasted the write and read commands from my program below since I think these are the problem. The program should take the plaintext file and encrypt it using the key provided.
MY PROBLEM: When I execute the program using "client [plaintext] [key] [port]" the program returns "Reading data from client -- 140 bytes" and then just hangs. I can hit ctrl-c and the program prints the correct output for ptext and ktext and that 37 bytes were sent back to the client (which is the correct number of bytes). I feel like the encrypted text should print as well but it does not.
TWO QUESTIONS:
1) Why does the program hang?
2) Why does it seem like data is written from the server to the client but the client does not read any of the data?
Thank you in advance for any help you can offer.
CLIENT
n = write(sockfd,ptext,strlen(ptext));
bzero(crypt_text, BUF_MAX);
bzero(buffer, BUF_MAX);
while((n = read(sockfd,buffer,BUF_MAX))>0){
printf("Reading data from Server -- %d bytes\n",n);
strcat(crypt_text, buffer);
bzero(buffer,BUF_MAX);
}
if (n < 0){
error("ERROR reading from socket");
}
printf("%s", crypt_text);
SERVER
while((n = read(newsockfd,buffer,512))>0){
printf("Reading data from client -- %d bytes\n",n);
strcat(full_text, buffer);
bzero(buffer,BUF_MAX);
}
if (n < 0){
error("ERROR reading from socket");
}
bzero (ptext,BUF_MAX);
bzero (ktext, BUF_MAX);
strcpy(ptext, strtok(full_text,"["));
strcpy(ktext, strtok(NULL, "["));
printf("ptext length ==%s %d\n\n",ptext,strlen(ptext)); //Prints the correct plain text
printf("ktext length ==%s %d\n\n",ktext,strlen(ktext)); //prints the correct key
crypt_text = encrypt(ptext, ktext);
n = write(newsockfd,crypt_text,strlen(crypt_text));
printf("WRITE TO CILENT ==== %d",n); //This returns the correct number of bytes that should be sent back to client
if (n < 0){
error("ERROR writing to socket");
}
As is, your client and server will always hang waiting for each other. This is because read() blocks by default until new data is available to fetch from the file (in this case, a socket).
Look carefully at the code:
The client writes once into the socket before entering the read loop
The server only reads from the socket (well, further down there is a write(), but it will never reach it). The first time the loop runs on the server, it will read the data that the client initially wrote into the socket.
The server processes the data it just read and concatenates it to full_text. Then it goes back to the loop condition, where it calls read() again. read() blocks because there is nothing else to read from the socket at this point.
The client enters a similar loop where it attempts to read from the socket, expecting messages from the server.
At this point, both the server and the client are blocked waiting for messages from each other, which will never happen.
Tu put it another way: you only wrote to the socket once, and somehow you expect to read it multiple times.
You have to rethink your design. Go back to the problem description, work your way through a simple protocol, dry run it on paper, and then implement it - that's how it's done in the real world :)
There are other bugs in your code. For example you write this:
strcat(full_text, buffer);
But buffer is not NUL terminated. n bytes have been read, the rest of the buffer is indeterminate. You should set a '\0' byte at offset n and only try reading BUF_MAX-1 bytes to keep a byte available for all cases and do this:
buffer[n] = '\0';
strcat(full_text, buffer);
Furthermore, you do not test if there is enough room available in full_text for the n+1 bytes strcat will copy at the end.
On another front, packets can be sliced and diced into chunked of different sizes when received by the server. Buffering is required to ensure a reliable client / server communication. To enable this buffering, you need to devise a protocol to determine when a packet has been fully received: a simple protocol is to transmit lines terminated by '\n'.
I'm new to this forum, so I'm sorry if my question is not correctly asked. I'll try to be as clear as possible.
I'm trying to code two programs (client.c and server.c, using TCP sockets) in Linux, with the following behavior:
Client sends messages to Server that contain commands (ls, mkdir, etc) to be run by Server.
Server runs these commands, and sends program output (stdout) back to Client.
Client prints the recieved program output.
So far, I have this:
server.c:
/*After creating socket with socket(), binding to address and port,
putting in listening mode and accepting connection*/
dup2(sock_client,1); //redirect stdout
while(1){
recv(sock_client,buf,MAX_MSG_LENGTH,0);
/*If the message recieved was END_STRING, exit this loop*/
if (strncmp(buf, END_STRING, MAX_MSG_LENGTH) == 0)
break;
system(buf);
}
client.c:
/*After creating socket and connecting*/
while(fgets(buf,MAX_MSG_LENGTH,stdin)){
send(sock,buf,MAX_MSG_LENGTH,0);
if (!strncmp(buf,END_STRING,MAX_MSG_LENGTH)){
/*If the message recieved was END_STRING, exit this loop*/
break;
}
read(sock,buf,MAX_MSG_LENGTH); //read stdout from program
printf("%s\n",buf);
}
My problem is that, if a command has a long output, there's some "garbage" left from it when showing the output of the next commands, so I was wondering if there was a way to flush the socket (apparently not, based on my google research), or maybe to accomplish the expected server-client behavior in some other way.
Thank you!
EDIT:
Ok, I've finished the client. Here's the code:
client.c:
/* After creating socket and connecting*/
while(fgets(buf,MAX_MSG_LENGTH,stdin)){
send(sock,buf,MAX_MSG_LENGTH,0);
if (!strncmp(buf,END_STRING,MAX_MSG_LENGTH)){
/*If the message recieved was END_STRING, exit this loop*/
break;
}
while(1){
read_size = read(sock,buf,MAX_MSG_LENGTH);
/*Print read_size characters from buf*/
printf("%.*s\n", read_size, buf);
if (read_size < MAX_MSG_LENGTH){
/*Keep on reading until read_size < MAX_MSG_LENGTH, then exit this loop*/
break;
}
}
/*Clear buffer, just in case*/
for (i = 0; i < MAX_MSG_LENGTH; i++){
buf[i] = 0;
}
Just as a comment, this program will not work properly if the command sent to the server doesn't have any standard output (for example, mkdir new_directory), since, in this case, read() will leave the client permanently blocked, causing the server to never recieve the next command to be run or the END_STRING message to leave the program from the client. You could probably fix this by using a non-blocking socket and using select() to read from socket, just like synther suggested. Additionally, in the server, after the system(buf); line, you should add fflush(0), which will flush all the buffers (including the socket, which could be useful if the command send by the client has a really short output).
Thanks a lot!
Thank you for your answers!
I tried adding this to my client.c code:
/*After creating socket and connecting*/
while(fgets(buf,MAX_MSG_LENGTH,stdin)){
/*Send command to server*/
send(sock,buf,MAX_MSG_LENGTH,0);
if (!strncmp(buf,END_STRING,MAX_MSG_LENGTH)){
/*If the message recieved was END_STRING, exit this loop*/
break;
}
while(1){
read_size = read(sock,buf,MAX_MSG_LENGTH); //read stdout from program
printf("%.*s\n", read_size, buf);
if (read_size < MAX_MSG_LENGTH){
/*Exit this loop when reading less that MAX_MSG_LENGTH*/
break;
}
}
/*Clear the 'buf' array. I don't know if this is really necessary*/
for (i = 0; i < MAX_MSG_LENGTH; i++){
buf[i] = 0;
}
}
And now, after every command, the client only prints the output of the last command sent. I will test it more thoroughly and edit my original post if this solution is correct, so thanks a lot!
Perhaps, you get "garbage" in client when your command's output exceeds MAX_MSG_LENGTH. read(sock,buf,MAX_MSG_LENGTH); reads just MAX_MSG_LENGTH bytes from socket, remaining chars in socket are read the next time when you except it from the next command.
You can fix it in multiple ways in client.
read returns the actual number of bytes read. You can compare it with MAX_MSG_LENGTH and decide to read one more time or not. But if your actual data is exactly MAX_MSG_LENGTH bytes then you decide to read again and read blocks waiting data that is not available at the moment (and stdin blocks too, user can't send new command).
Use non-blocking socket to fix issue in 1. read will return immediately when no available data.
Add end-of-command marker to your server's output and client will know when to stop reading and switch to stdin reading.
Use select() mechanism to read from socket and user input "simultaneously". It allows to read from multiple file descriptors (socket and stdio) when data available on any of them.
Additionally, you use the same buffer for user commands and server responses. Typically, user commands are shorter then server output and buf could contain parts of last server outputs. Then you send this mix of user command and last server output to server.
And, as stated above, read returns the actual number of bytes read. You should print the exactly received number of bytes from buf, not all the data.
int ret = read(sock,buf,MAX_MSG_LENGTH); //read stdout from program
printf("%.*s\n", ret, buf);
I am trying to send an array of strings over a socket and receive it on the other end.
Here is my client side ( side sending the data ) :
char* client_hello[] =
{
"Type client_hello",
"Version SSLv3.0",
"Session ID 1",
"Random 1as2#3%$h&KF(*)JAGG&(#H%A$D#J*##",
"Cipher-Suites TLS_RSA_WITH_RC4_128_SHA",
"Compression null(0)"
};
SendBytes = send(sock, client_hello, 6, 0);
This is my Server side ( side receiving the data ):
int inMsgLen = recvfrom(clntSock, inMsg, 1024, 0,(struct sockaddr *)&clntAddr, (socklen_t*)&clntAddrLen);
if (inMsgLen < 0) {
//printf("Error in recvfrom() errno=%d\n", errno);
continue;//exit(1);
}else if (inMsgLen > 1024) {
printf("Received message too long (size=%d)\n", inMsgLen);
exit(1);
}else{
printf("Received Message: %s\n", inMsg);
}
inMsg is declared as char inMsg[1024];
This is what the output is on the server side :
Received Message: +?
What am I doing wrong ? How can I send/receive the entire client_hello array ?
I am trying to send an array of strings over a socket and receive it on the other end.
But the code is sending the first six bytes of an array of char* (as mentioned by WhozCraig in a comment to the question):
SendBytes = send(sock, client_hello, 6, 0);
the receiving side is reading the pointer addresses and treating them as strings, hence the junk.
To correct, send each string in turn but you will need to create a protocol that defines the beginning and end of a string as the bytes are written and read from sockets as streams, not some notion of message. For example, prefixing each string with its length (a sequence of digits terminated by a new-line character would be one simple option) followed by the actual string:
18\nSession ID 124\nCompression null(0)0\n
The receiving end would read to the new-line character, convert what was read to an int, allocate a buffer to contain the string (remembering space for the null terminator) and then read that number of char from the socket. A length of zero could be used to terminate the transfer of the list of strings.
Note that a call to send() may result in only a part of the requested data being sent. The code needs to cater for this by keeping track of the number of bytes send so far and indexing into the buffer being sent.
If you try to make a loop, using "for" to send... maybe is possible to server understand. Making client_hello[i], line by line..
Am back with C sockets question.
I am trying to receive a char array from a client via TCP. I have the following recv code:
char buffer[2048];
int recvBytes = 0;
while (1) {
if ((clntSockfd = accept(servSockfd, (struct sockaddr *) &clntAddr, &clntSockAddrLen)) == -1) {
printf("Unable to accept client connection\n");
exit(1);
}
else {
printf("Client connection accepted!\n");
}
/* clear buffer */
memset(buffer, 0, sizeof(buffer));
recvBytes = recv (clntSockfd, buffer, sizeof(buffer), 0);
printf("Bytes received: %i\n", recvBytes);
printf("Char array received: %s\n", buffer);
}
I noted that upon execution, recvBytes shows zero in the first iteration. It's only after the second iteration that it picks up the incoming char array.
I would like to find out will recv block until I receive data from the incoming socket? How should I discard the unwanted chars in the buffer - i.e. drop the chars received from the first iteration.
Many thanks!
-- edit ---
Hi all, I have appended the console output from eclipse.
**... <- initialization stuff
Binding socket to port
Socket binded
Start listening on port 8081.
Client connection accepted! *while loop - first iteration
Bytes received: 0 *while loop - first iteration
Char array received: *while loop - first iteration
Client connection accepted! *while loop - second iteration
Bytes received: 22 *while loop - second iteration
Char array received: 1~Message~HowAreYou? *while loop - second iteration**
Hope the above console output illustrates my questions clearer, regarding the first and second iterations. From the above, the first iteration is not receiving any bytes but recv does not block. I thought recv was supposed to block until it receives bytes?
I believe the recv only returns 0 if the remote end closes the connection (for stream sockets such as TCP) or if a packet with no payload is received (datagram sockets such as UDP).
If the socket has been set to non-blocking mode (default is blocking), and there's no data yet, you'd get an error code, either EAGAIN or EWOULDBLOCK depending on the OS.
In any case, each time recv returns, the new data will be stored at the beginning of the buffer. It won't append to previously received data unless you calculate a pointer designed to store new data after the old.
If your socket is a blocking socket, then recv function will block till you get some data. recv function will return 0 only when the other side closes the connection on most systems.
I suggest you recheck your code and execution and let us know the exact output.
Refer here and here for more details.
If you know what to expect of the data that you receive you can drop the first set of characters. For example if you know what will the length of the packet be or the source of the message or the header information then you can validate and ignore the first set of characters.