I'm coding two programs that communicates via sockets sendinc char * strings.
Sometimes, read() reads less bytes than it should, so I gotta loop that read() till all the bytes are read. But, for example, if I want to read a string of 100 bytes, and read() only receives 60 (40 are missing in the socket buffer), means the string has only data in it's 60 first positions. Now I'd want to loop the read() to read those extra 40 bytes but, how can I tell the read() function to store those bytes from the position 60 of the previously filled string in order not to overwrite the information before read?
char string[100];
ssize_t total_bytes = 100;
ssize_t bytes_read = 0;
do {
//How can I read and store the array of chars in the variable string being string[bytes_read] the starting point in each iteration?
bytes_read = read(socket, string/*?*/, total_bytes);
total_bytes -= bytes_read;
} while(total_bytes > 0);
You can add an integer to the pointer (converted from the array, pointing at the first element of the array) to advance the position to start writing what is read.
bytes_read = read(socket, string + (100 - total_bytes), total_bytes);
If you definitely want the start point to be string[bytes_read] (it will make it overwrite some data if 3 or more reads are done):
bytes_read = read(socket, string + bytes_read, total_bytes);
or this may be easier (straight-forward):
bytes_read = read(socket, &string[bytes_read], total_bytes);
Related
I've recieved this assignment where I have to read from a file.txt(max size 4096B) four times, basically splitting it in 4 strings of equal size. I have to fill this structure(just consider field 'msg', i think the problem is there):
struct message {
long mtype
int nclient;
int pid;
char path[151];
char msg[1025];
};
I used an array of 4 struct message to store all 4 parts
This is my read:
struct message msgs[4];
for (int i = 0; i < 4; i++) {
msgs[i].nclient=pos+1;
msgs[i].mtype = 42;
msgs[i].pid = getpid();
strcpy(msgs[i].path, filespath[pos]);
if (read(fd, msgs[i].msg, nMsgSize[i]) == -1)
ErrExit("read failed");
printf("I've read: %s\nMSGSize: %d\nPath: %s\n",msgs[i].msg, nMsgSize[i], msgs[i].path);
}
I tested it on a file "sendme_5.txt" that has this text in it:
ABCD
And this is my output:
I've read: A MSGSize: 1 Path:
/home/luca/Desktop/system_call_meh/myDir/joe_bastianich/bruno_barbieri/sendme_5.txt
I've read: BP"�> MSGSize: 1 Path:
/home/luca/Desktop/system_call_meh/myDir/joe_bastianich/bruno_barbieri/sendme_5.txt
I've read: C#��;�U MSGSize: 1 Path:
/home/luca/Desktop/system_call_meh/myDir/joe_bastianich/bruno_barbieri/sendme_5.txt
I've read: D�.�>� MSGSize: 1 Path:
/home/luca/Desktop/system_call_meh/myDir/joe_bastianich/bruno_barbieri/sendme_5.txt
If i try to read the full file without dividing it in 4(with only one read), it displays it correctly.
The problem started when i changed the field char path[151]. We had to set the max size to 151 from PATH_MAX(4096) after a change in the assignment, but i dont know if it's related.
What is the problem here?
As stated above, read does not know what a null-terminated string is. It deals with raw bytes, making no assumptions about the data it reads.
As is, your strings are possibly not null-terminated. printf("%s", msgs[i].msg) might continue past the the end of the read data, possibly past the end of the buffer, searching for a null-terminating byte. Unless the data read happens to contain a null-terminating byte, or the buffer was zeroed-out beforehand (and not completely filled by read), this is Undefined Behaviour.
On success, read returns the number of bytes read into the buffer. This may be less than requested. The return value is of type ssize_t.
When using this system call to populate string buffers, the return value can be used to index and place the null-terminating byte. An additional byte should always be reserved for this case (that is, always read at most the size of the buffer minus one: char buf[256]; read(fd, buf, 255)).
Always check for error, or the return value of -1 will index the buffer out-of-bounds.
Assuming nMsgSize[i] is the exact size of the msgs[i].msg buffer:
ssize_t n;
if (-1 == (n = read(fd, msgs[i].msg, nMsgSize[i] - 1)))
ErrExit("read failed");
msgs[i].msg[n] = 0;
printf("READ:%zd/%d expected bytes, MSG:<<%s>>\n", n, nMsgSize[i] - 1, msgs[i].msg);
Aloha,
I'm new here, so please take it easy on me.
I'm trying to read a file with function read() and then write() to a file or a file descriptor. My function successfully reads a file, but a problem occurs when I try to read a larger file(in my example size of 40,000 bytes).
I think that I must write a while loop, which will be reading until the end of a file, but I am stuck on the idea of how to..
(I open a file or file descriptor in main of the program)
My function( also convert binary input char data and writes to the ASCII) :
void function(int readFrom,int writeOn){
char buffer[100];
int x = read(readFrom, buffer, sizeof(buffer));
int size= x/8;
int i;
for(i=0; i<size; i++){
char temp[sizeof(int)-1];
sprintf(temp,"%d",buffer[i];
write(writeOn, temp, sizeof(temp));
}
}
You need to check return value of functions read and write. They return the number of bytes read/written that may be less than the number that you passed as third argument. Both read and write must be done in a loop like:
int bytesRead = 0;
while (bytesRead < sizeof(buffer)) {
int ret = read(readFrom, buffer + bytesRead, sizeof(buffer) - bytesRead);
if (ret == 0)
break; / * EOF */
if (ret == -1) {
/* Handle error */
}
bytesRead += ret;
}
You use sprintf() to convert characters from buffer into a very small buffer temp. On most current systems, int is 4 bytes, so your printf causes buffer overflows for char values greater than 99 (ASCII letter 'c'). Note that char can be signed by default, so negative values less than -99 will require 5 bytes for the string conversion: 3 digits, a minus sign and a null terminator.
You should make this buffer larger.
Furthermore, I don't understand why you only handle x/8 bytes from the buffer read by the read() function. The purpose of your function is obscure.
I was running into a problem i couldnt really solve so I restarted.
I had a problem with Data encapsulation or more specific with no encapsulation. So after I figured out, that encapsulation is useful, I started rewriting the code.
Now I run into a different Problem. Somehow my send and recv calls are not working as I want them to be.
Here is the part where I send:
char to_send[] = "hello. I am the Data.";
// get size of data
int len = strlen(to_send);
char slen[len];
sprintf(slen,"%d",len);
printf("%s\n",slen);
// send size of data
if(send(comm_fd,slen,len,0)<0){perror("Error on send"); exit(1);}
// send data
if(send(comm_fd,to_send,len,0)<0){perror("Error on send"); exit(1);}
And here Part where I recv:
// getting size of bytes to recv
char buf[1000];
bzero(buf,1000);
int rec = recv(comm_fd, buf, 100,0);
printf("rec\n: %i",rec);
printf("buf\n: %s\n", buf);
int buffsize;
buffsize = atoi(buf);
bzero(buf,1000);
printf("buffsize: %i\n",buffsize);
// recv the bytes
bzero(buf,1000);
rec = recv(comm_fd, buf, buffsize,0);
printf("rec\n: %i",rec);
printf("%s",buf);
So my problem now is: I can recv the size of the next Data and print it. But the Data itself is not showing up.
Can someone help me? I think I'm doing major things wrong (I'm new to C and to Network programming)
Thanks in advance
Two things with that first send call:
if(send(comm_fd,slen,len,0)<0){perror("Error on send"); exit(1);}
Here you send len number of bytes, but len is the length of to_send and not the length of slen. You will most likely send data from outside the initialized parts of slen which leads to undefined behavior
The second problem is that you send the length of to_send as a variable-length string, so the received doesn't actually know how much to receive. In your case you could actually (and probably do) receive the length and the string in a single recv call. At least if you're using TCP (streaming) sockets.
Both of these problems can be solved by making slen a fixed-size array, big enough to hold the largest numbers you can think of (ten digits is usually enough), and then send this fixed-length array using sizeof slen .
Perhaps something like this:
// Ten digits, plus string terminator
char slen[10 + 1];
// Prefix length with zeroes, and don't overflow the buffer
snprintf(slen, sizeof(slen), "%010d", strlen(to_send));
// Send the whole array, including terminator
send(comm_fd, slen, sizeof slen, 0);
Then on the receiving side, you could do
// Ten digits, plus string terminator
char slen[10 + 1];
// Receive the whole string, including terminator
recv(comm_fd, slen, sizeof(slen), 0);
// Convert to a number
size_t len = strtoul(slen, NULL, 10);
// Now receive `len` bytes
Note that I have no error checking, which you should have.
I have used pipe and I have to read from this pipe. But problem is this:
ssize_t read(int fd, void *buf, size_t count)
I don't know how many characters is stored in the reading end of pipe, so I can't assign some number to count. I need this to store in the buffer.
How can I number of characters stored in this pipe?
With regards
I don't know how many characters is stored in the reading end of pipe
Don't worry about it. There are advantages (e.g. atomicity) to not trying to write/read more than PIPE_BUF bytes at shot. In reality you will probably get a bunch of short reads anyway.
#define READ_BUFFER_SIZE PIPE_BUF
unsigned char mybuffer[READ_BUFFER_SIZE];
ssize_t bytesread = 1;
while ((bytesread = read(pipefd, mybuffer, READ_BUFFER_SIZE)) > 0)
{
concat to bigger buffer, realloc if necessary
}
Just use a reasonably sized buffer, and read as much as you can. Repeat that. The function returns the number of bytes read.
You need not know before hand how many bytes are there and pass that as as a value for count.
You can define buffer of maximum data size that you can expect and read from the fd until data is present.
char buf[MAX_DATA_SIZE] = {0};
bytes_read = 0;
while(n > 0)
{
n = read(fd,buf+bytes_read,MAX_DATA_SIZE)
bytes_read = bytes_read + n;
}
You can simply request the number of characters up to the size of your buffer, and do so repeatedly in a loop, e.g:
char* buf = malloc(1024);
do {
bytes_read = read(fd, buf, 1024);
// store buf somewhere else so you can use it in the next iteration
} while (bytes_read > 0)
free(buf);
How can I store the result of Serial.readBytesUntil(character, buffer, length) in a buffer while I don't know the length of the incoming message ?
Here is a little code that makes use of realloc() to keep growing your buffer. You will have to free() when you're done with buf.
int length = 8;
char * buf = malloc(length);
int total_read = 0;
total_read = Serial.readBytesUntil(character, buf, length);
while(length == total_read) {
length *= 2;
buf = realloc(buf, length);
// Bug in this line:
// total_read += Serial.readBytesUntil(character, buf+total_read, length);
// Should be
total_read += Serial.readBytesUntil(character, buf+total_read, length-total_read);
}
*Edit: fixed a bug where readBytesUntil would have read off the end of buf by reading length bytes instead of length-total_read bytes.
make the buffer big enough for the message. Don't know the maximum length of the message? Use length to control the characters read, then continue reading until character encountered.
int bytesRead = Serial.readBytesUntil(character, buffer, length);
You could create a buffer that is just smaller than the remaining RAM and use that. The call to find the remaining ram (as I've posted elsewhere) is:
int freeRam () {
extern int __heap_start, *__brkval;
int v;
int fr = (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
Serial.print("Free ram: ");
Serial.println(fr);
}
Regardless, you should make sure you only read into as much RAM as you actually have.
One answer is that when a program reads serial bytes it typically does NOT store them verbatim. Rather, the program examines each byte and determines what action to take next. This logic is typically implemented as Finite State Machine.
So, what does your specific serial stream represent? Can it be analyzed in sequential chunks? For example: "0008ABCDEFGH" says that 8 chars follow the 4 character length field. In this silly example your code would read 4 chars, then know how much space to allocate for the rest of the serial stream!