recv returns old data - c

This loop is supposed to take data from a socket line by line and put it in a buffer. For some reason, when there is no new data to return, recv returns the last couple lines it got. I was able to stop the bug by commenting out the first recv, but then I cant tell how long the next line will be. I know it's not a
while(this->connected){
memset(buf, '\0', sizeof(buf));
recv(this->sock, buf, sizeof(buf), MSG_PEEK); //get length of next message
ptr = strstr(buf, "\r\n");
if (ptr == NULL) continue;
err = recv(this->sock, buf, (ptr-buf), NULL); //get next message
printf("--%db\n%s\n", err, buf);
tok[0] = strtok(buf, " ");
for(i=1;tok[i-1]!=NULL;i++) tok[i] = strtok(NULL, " ");
//do more stuff
}

The manual states:
MSG_PEEK
This flag causes the receive operation to return data from the
beginning of the receive queue without
removing that data from the queue.
Thus, a subsequent receive call will
return the same data.
So I think you're getting the correct behavior, but perhaps expecting something else.

Your problem is that when you use recv with MSG_PEEK, you are giving recv the whole size of your buffer, if there are two lines already there, like "HELLO\r\nHELLO\r\n" it will read them into your buff.
ptr would point to the first \r\n, then you call recv with (ptr - buff) which will make recv to read only the first HELLO, into buf, but since you already READ that info into buff, you will process the two lines, but leaving \r\nHELLO\r\n in your queue, because you did not fully read them.
Next time you would peek into it and have info hanging that you already processed, leading you to believe that you are getting repeated data.
(I hope I wrote this clear enough, it is a very confusing bug you got there :)

I needed to add 2 to the length of the second recv so I'd take the "\r\n". Otherwise, it sees the first "\r\n" and thinks the line of the end is buf[0].

Hi i find the solution :
void receiver(int accepted_client) {
// Ready to receive data from client.
while (true) {
char buffer[256];
recv(accepted_client, &buffer, 255, 0);
int sum = 0;
for (int i = 0; i < 256; i++) // Check that buffer value is zero or not.
sum |= buffer[i];
if (sum != 0) {// If buffer value is not zero then start to print the new received message.
string string_message(buffer);
cout << string_message << endl;
}
memset(&buffer, 0, 256); // Clear the buffer.
}
}

Related

How to properly concatenate a string received in parts?

I'm using sockets in C, I have a client that will send a message and the size of the message and the server that will receive this message in buffers of shorter size. The message is being sent correctly, but I'm having problems when I try to concatenate all the buffers in a single string.
The client:
char *buffer = "Hello from the client you're receiving this message";
int bytes_sent;
long msgSize = strlen(buffer);
printf("Buffer Size: %ld\n", msgSize);
int msgFileSize = send(SocketFD, &msgSize, sizeof(msgSize),0);
bytes_sent = send(SocketFD, buffer, strlen(buffer), 0);
The server:
char buffer[8];
ssize_t recsize;
long msgSize;
int msize = recv(ConnectFD, &msgSize, sizeof(msgSize), 0);
int total_byt = 0;
printf("Full Message Size: %ld\n", msgSize);
char full_msg[msgSize];
while (total_byt < msgSize) {
recsize = recv(ConnectFD, (void*)buffer, sizeof buffer, 0);
total_byt += recsize;
strcat(full_msg, buffer);
if (recsize < 0) {
fprintf(stderr, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}
printf("recsize: %d\n ", (int)recsize);
sleep(1);
printf("datagram: %.*s\n", (int)recsize, buffer);
}
printf("full message: %s\n", full_msg);
The output of the server looks like this:
Full Message Size: 51
recsize: 8
datagram: Hello fr
recsize: 8
datagram: om the c
recsize: 8
datagram: lient yo
recsize: 8
datagram: u're rec
recsize: 8
datagram: eiving t
recsize: 8
datagram: his mess
recsize: 3
datagram: age
full message: ��9�Hello from the client you're receiving this message mess
Few problems here.
strlen returns length excluding the null char.
long msgSize = strlen(buffer);
Thus you need to have 1 additional place to hold null char.
char full_msg[msgSize+1];
full_msg[0] = '\0';
There is undefined behavior with strcat as buffer is not null terminated.
recsize = recv(ConnectFD, (void*)buffer, sizeof buffer, 0);
strcat(full_msg, buffer);
use
strncpy(full_msg, buffer, sizeof buffer);
Finally null terminate the full_msg after loop to be sure.
while (total_byt < msgSize) {
….
}
full_msg[total_byt] = '\0';
It looks like your full message variable is not initialized. It is starting out with random data in it, which is causing your unexpected results. Use the following code to initialize it:
char full_msg[msgSize] = "";
Also, using strcat in the way you are is not safe. You must keep track of how much space is left in full_msg or you will have a buffer overrun situation. strncat is the function that can solve this problem.
There's absolutely no point reading into a separate buffer and then concatenating that into another buffer. Just read directly into full_msg.
Even if you were going to append block by block, strcat is not the right way to do it. strcat needs to start by finding the current end of the output buffer, which it can only do by sequentially scanning from the beginning looking for a NUL byte. As the buffer gets more and more data, those scans get longer and longer, leading to quadratic time complexity. This particular unnecessarily quadratic append is often called a "Schlemiel the Painter" algorithm.
The scan is unnecessary because you already know where the new data should be appended, since you carefully keep track of how many bytes you've already read. So each successive block should be placed total_byt bytes past the beginning of the buffer. (That is, at location full_msg+totalbyt.) You also know how long the data to append is, so you can use memcpy to put the newly-read chunk in the right place.
Uding memcpy will also avoid the problems which will occur if data can contain NUL bytes. (Since strcat returns immediately when it encounters a NUL, your current code will not work on messages which do include NUL.)
Note thatrecv does not NUL-terminate the input received, so your strcat will also do the wrong thing if the recv doesn't fill the buffer (and it only works with the buffer as written because it happens to be the case that
There is at least one other problem with your code: nothing guarantees that recv will stop reading at the end of a message, since the sockets library doesn't know where TCP messages end. (UDP message endpoints are marked, but you can't receive a UDP message in multiple chunks.) Again, since you keep track of the number of bytes read, and you know the length of the message (once you've read that data, at least), you can easily work out what the maximum number of bytes to read is.

C - Failing to read socket after about 30 reads

so I have two processes, one client-process one server-process. The user can issue a command to the client, when a user enters a command the client will send the command length to the server, and after that it will send the actual command.
The server then sends back first the length of the response and then a response.
I can do 5-30 commands or so with no problem at all, but at some point it fails to read enough bytes, despite the correct response size being received.
The server sends the response in the following way:
str[0] = '\0';
unsigned long int totalSize = 0;
while ((fgets(outBuf, MAXOUTPUT, myFile)) != NULL)
{
strcat(str, outBuf);
}
uint32_t *un = 0;
totalSize = strlen(str);
*un = htonl(totalSize);
result= send(clientFD, un, sizeof(uint32_t), 0);
if(result < 1)
{
printf("Failed sending message size to client");
exit(-1);
}
while(token != NULL)
{
size_t length = strlen(token);
token[length] = '\n';
write(clientFD, token, length + 1);
token = strtok(NULL, "\n");
}
The client has received the message length correctly(verified with prints) and reads the response this way:
result = read(socketFD, recvBuf, bufferlen); //bufferlen is response size
if(result < bufferlen)
{
perror("read()");
exit(-1);
}
I have verified that the client receives the correct message length every time, including the last one where it fails to read.
So my question is: What are likely reasons that my read sometimes fail to retrieve the full response? It happens after doing about 5-30 commands or so usually, and the perror returned is Error 0 (aka no error to be found).
As an additional note, the commands tested are
ls -la, ls -l, ls.
I have not found a pattern in which commands cause the crash, but I have combined them a lot.
Also: Both the client and server are 32 bit and being run on the same machine locally.
read() (especially on sockets) returns as soon as some data is available, it may always return less bytes than you asked for. In this case, you will need to repeat the read until you have read enough data:
size_t bytes_read = 0;
while (bytes_read < bufferlen) {
result = read(socketFD, recvBuf + bytes_read, bufferlen - bytes_read);
if (result < 0) {
perror("read()");
exit(-1);
}
bytes_read += result;
}
The TCP socket works on a byte stream concept. The server is adding bytes to the byte stream, and the client is consuming them. The socket need not send all of the bytes at once; it will eventually send them and they will be read in order at the other end. Messages are not guaranteed to be kept whole. You encounter a problem when you can read the bufferlen field but the whole corresponding message has not arrived yet.
Your client needs to continue reading from the socket until bufferlen bytes have been read.
Also be aware that the act of reading the bufferlen field may also need to be completed with multiple reads.

C: tcp recv not clearing old data

I have the following code in server.c
while (1) {
char msg[1024];
recv(fd, msg, 1024, 0);
}
From client, first, I sent "hello world".
And then I received "hello world" in server.
I then sent "hexx" to server.
But I received "hexxo world" on server.
It seems as if msg wasn't cleared fully.
Please let me know what I'm doing wrong.
Cheers.
You are allocating 1024 bytes for message and never zeroing that data. You are just reading into the same buffer over and over. First pass it reads "hello world" in the second pass you are putting "hexx" in the same starting address resulting in "hexxo world"
As DoxyLover mentions you can null terminate the newly read string and get what you are looking for.
tcp recv not clearing old data
Who said it would? Not that it should be necessary. You're ignoring the count returned by recv(). After calling recv(), there are three possibilities:
Return value of -1: an error; call perror().
Return value of 0: end of stream: close the socket and exit the read loop.
Return value is positive: you have received exactly that many bytes into your buffer, and you should not assume that any data beyond that count is valid.
At present you're doing none of these things correctly.
read() does not null terminate the buffer. Therefore, you are seeing the old data left over in the buffer.
What you want is something like:
while (1) {
char msg[1024];
ssize_t n = recv(fd, msg, 1023, 0);
if (n >= 0)
msg[n] = '\0';
}
Note that I am limiting the read to one less than the size of the buffer to allow space for the null byte. Obviously, this only works with text data. With binary data, you need to record the return value from read() and use that as a byte count when processing the buffer. For example, to copy data from one socket to another:
while (1) {
char msg[1024];
ssize_t n = recv(fd, msg, 1024, 0);
if (n > 0)
send(second_fd, msg, n, 0);
}
All of this is very simplified - you need error checking, check the return from read() to make sure any bytes were received, check the return from send() to make sure all of the byte were sent, etc.

C parsing HTTP Chunked transfer encoding response

I am developing a client that needs to parse Chunked-type HTTP transfers. I've beat my head against the wall trying to figure out the error with the following, and would appreciate it if someone might be able to catch my error a bit quicker. To sum up the issue: it seems as though, the client does not receive ALL of the chunk, thereby screwing up the rest of the process. Thanks in advance!
while(cflag){
pfile_chunk = malloc(CHUNK_SIZE+1);
memset(pfile_chunk, 0, CHUNK_SIZE);
cPtr = pfile_chunk;
cPtr2 = NULL;
k=0;
while(*(cPtr-1) != '\n'){
k++;
recv(sock, cPtr, 1, 0);
cPtr = pfile_chunk+k;
}
cPtr2 = strchr(pfile_chunk, '\r');
*cPtr2 = '\0';
sscanf(pfile_chunk, "%x", &l);
if(l == 0)
break;
printf("\nServer wants to deliver %ld bytes.\n", l);
pfile_chunk = realloc(pfile_chunk, l+1);
memset(pfile_chunk, 0, l);
recv(sock, pfile_chunk, l, 0);
fputs(pfile_chunk, f);
printf("GOT THIS, SIZE %ld:\n%s\n", strlen(pfile_chunk), pfile_chunk);
//get next \r\n bytes.
recv(sock, NULL, 2, 0);
}
At the very least, you should check the return value of recv to see if you are getting the number of bytes you are expecting to get.
A short read is definitely possible on the network, since the system call will return whatever is available in the socket receive buffer at the time you make the call.
Implement a loop until you have read in your entire chunk, or pass the MSG_WAITALL flag to recv in the last parameter. However, you still need to check for an error from recv.
ssize_t r = recv(sock, pfile_chunk, l, MSG_WAITALL);
if (r < l) {
/* check for errors ... */
} else {
/* got the data */
}
It looks as though your very first dereference for the check in your while loop will access before the beginning of your array, which is likely not to be desired behavior. Hopefully, that memory location usually won't contain \n. That could mess up your read. I expect it probably contains some information to do with your malloc, which is unlikely to be \n, so you might never see a problem from that.
Also, hopefully you can trust the other end of the socket not to send more than CHUNK_SIZE+1 before they give you a \n. Otherwise, it could seg-fault out. Normally, though, I would expect a sender to just send 10 or fewer ASCII numeric characters and a CRLF for a chunk header anyways, but they could theoretically send a bunch of long chunk extension header fields with it.
Apart from that, there's just the more important issue already found by user315052 that you should either tell the recv method to wait for all the data you requested, or check how much data it actually read.

How to send and receive bytes with socket apis?

Hi i have written a server application which accepts a name from the client which usually is a file name.It opens the file ,reads the contents into a buffer and then transmits the buffer over the ethernet using send().But the problem arises in the client side where all the bytes are not received successfully.I receive only a part of what i send.
For your reference ,here's the code snippet for the server side:
Server:
fp = fopen(filename,"r+");
strcpy(str,"");
fseek(fp, 0L, SEEK_END);
size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
fread(str, size, 1,fp);
fclose(fp);
printf("Size of the file is : %d\n",size);
sprintf(filename, "%d", size);
n = send(nsd, filename, strlen(filename), 0);
while(size > 0){
n = send(nsd, str, strlen(str), 0);
printf("%d bytes sent successfully\n",n);
if(n == 0) break;
sentbytes = sentbytes + n;
size = size - sentbytes;
}
Please help me with writing the client app.I am currently confused about how to go about writing it.Shall i place the recv() part in a while(1) loop so that the client keeps running until all the bytes have been received successfully?
EDITED
For starters, you could both read from the file and write to the socket in chunks at the same time.
Since, you are transferring data over TCP, remember that data is transferred reliably as a stream and not as messages. So, don't make assumptions about how the data is recv'd except for the order.
Here is how it could be written:
open socket
open file
size_of_file = read_file_size(file);
send(socket, &size_of_file, sizeof(int), ...)
while (all is written)
read fixed chunk from file
write as much was read to the socket
cleanup // close file, socket
As for the recv part, I think it is best you send the file size over as an integer and keep reading in a while loop until you have recv'd as many bytes as you are sending from the server.
It's like this:
recv(socket, &size_of_msg, sizeof(int), ...)
while(all is read)
read fixed chunk from the socket
cleanup
Well I see atleast some issue with the way you are sending message over socket.
First from the man page of fread:
The function fread() reads nmemb elements of data, each size bytes
long, from the stream pointed to by stream, storing them at the loca-
tion given by ptr.
and what you are trying is this:
fread(str, size, 1,fp);
I assume what you meant was
fread(str, 1,size,fp);
Though it shold not casue the issue.
But the problem lies here:
n = send(nsd, str, strlen(str), 0);
printf("%d bytes sent successfully\n",n);
if(n == 0) break;
sentbytes = sentbytes + n;
size = size - sentbytes;
Though you are decreasing 'size' by decreasing by number of bytes successfully send, where are you extending str to point to new buffer location where data will be send.This will only resend initial bytes of the buffer repeatedly.
str += n; //Assuming str is char*
will solve your issue.
Using strlen doesn't seem appropriate. You've read the file, you know how long it is, so why do strlen? Either you'll just get the same result (so it's redundant) or you'll get something else (so it's a bug).
"Shall i place the recv() part in a while(1) loop so that the client keeps running until all the bytes have been received successfully?"
Something like that. Never presume that a recv() call got everything that was sent -- tcp/ip breaks messages into packets at a lower level, and recv() will return after reading whatever amount of data has actually been received at whatever point. You don't have to worry about that directly, except in so far as you do need to use some kind of protocol to indicate how long a message is so the receiver knows how much to read, then eg.:
char buffer[4096];
int msgsz = 600, // see below
sofar = 0,
cur;
while (sofar < msgsz) {
cur = recv (
socket_fd,
&buffer[sofar],
msgsz - sofar,
0
);
if (cur == -1) {
// error
break;
} else if (cur == 0) {
// disconnected
break;
}
sofar += cur;
}
WRT msgsz, you would include this somewhere in a fixed length header, which is read first. A simple version of that might be just 4 bytes containing a uint32_t, ie, an int with the length. You could also use a null terminated string with a number in it, but that means reading until '\0' is found.

Resources