Reputation: 15
I'm trying to read data from a socket in C. There will be two messages.
I am trying to send the size of the message to the socket so that the read() command will know when the message ends and can stop reading at that point. Otherwise, it will read both messages into one blob. The problem is that the read command sets the buffer to 0 even though it read > 0 bytes.
Here is the code:
n = read(newsockfd, buffer, sizeof(int));
int bytes_to_read = atoi(buffer);
fprintf(stdout, "Here is the size of the data to look for: %d", bytes_to_read);
/*read message*/
fprintf(stdout, "Reading first message.\n");
int bytesread = 0;
int chunk = bytes_to_read > 255 ? 255 : bytes_to_read;
do {
bzero(buffer,256);
n = read(newsockfd,buffer,chunk);
bytes_read += n;
fprintf(stdout, "The value of n is %d and here is the new buffer after the first read: %s and new buffer length is : %d\n", n, buffer, strlen(buffer));
strcat(plaintext, buffer);
size += 256;
plaintext = realloc(plaintext, size);
} while (bytes_read < bytes_to_read);
The output I get shows that n = 36 (as expected) but buffer is 0 and the length of buffer is 1.
Why would the read() command be setting the buffer to 0? Is there an easier way to tell read() where to stop reading?
EDIT: Based on the feedback I got, I drastically re-wrote this. Note that I know the client will send one packet containing the number of bytes in the data as a unit32_t, then it will send the data.
char * readText(int newsockfd) {
char * text = malloc(256);
char buffer[256];
int n;
int size = 256;
/*find out how many bytes are in the data*/
uint32_t bytes_to_read;
n = read(newsockfd, &bytes_to_read, sizeof(uint32_t));
bytes_to_read = ntohl(bytes_to_read);
/*read data from client*/
int bytes_read = 0;
int bytes_left = bytes_to_read;
/*the maximum we can read at one time is 255 bytes since that is the size of the buffer.
* the buffer could have been larger but we'd still have to check the data size and keep calling
* read() until we get all of the data.
* If the data to read is smaller than the buffer, then we just read it in one go. If the data is larger,
* then we read it in 255 byte-sized chunks until we have read all of it*/
int chunk = (bytes_to_read > 255) ? 255 : bytes_to_read;
do {
bzero(buffer,256);
n = read(newsockfd,buffer,chunk);
/*copy over the data we have read so far into the text buffer
We offset by the amount we have already read in so we do not overwrite the data already
in the array*/
memcpy(text + bytes_read, buffer, n);
bytes_read += n;
bytes_left -= n;
/*if we have less than 255 bytes left, just read that amount. This prevents read() from pulling in too much data and messing up the next read() call*/
chunk = (bytes_left > 255) ? 255 : bytes_left;
size += n;
/*grow the text variable by as much as we just read in. This makes room for
the next chunk of data. The next chunk could be as large as 255 bytes*/
text = realloc(text, size);
} while (bytes_read < bytes_to_read);
text[bytes_read] = '\0'; //null terminate our string so we can use string functions on it.
if (n < 0) error("ERROR reading from socket");
return text; }`
Upvotes: 0
Views: 2770
Reputation: 310913
There's no guarantee you received the entire length message.
You're reading it for sizeof int
bytes, which suggests binary data, but you're then calling atoi()
, which suggests null-terminated ASCII data in the form of a decimal string. Which is it?
If you're getting a return value of 36 that's how many bytes were received, and if the buffer contains {0, 1}
that's what was received too.
It simply isn't valid to just use strlen()
or strcat()
on an arbitrary array of bytes. These functions are for null-terminated strings. There is nothing about TCP that says every buffer you receive will be a null-terminated string, and nothing that says what you receive will even be printable.
What you're doing is simply not valid.
Upvotes: 3