C read() and write() while loop - c

Here is example code:
int nbajt; int buf[];
// we opened file and get descriptor fd
while ((nbajt = read(fd, buf, 5)) > 0) {
if (write(fd2, buf, nlbajt) == -1) {
perror("ERROR");
exit(1);
}
}
I don't understand how it is working when we use while loop. How many times this loop will proceed? (times of the lengs of buf?). Will nbajt has only values of 1 or 0 + buf file position will be changing 1 place after each loop step? So in first step we have nlbajt = 1 and we take buf first position char and then write it to fd2?. On the end we have nlbajt==0 so it means it's end of file? I would be grateful for checking if i am wrong.My main concern is how nbajt value is changing. How it is diffrent for this attitude:
nbajt = read(fd, buf, 5));
write(fd2, buf, sizeof(a));

The read() has the below prototype:
int read( int handle, void *buffer, int nbyte );
It returns number of bytes successfully read . 0 when EOF is reached.-1 when there is an error.
Yes nlbajt = 0 means EOF here.

Related

Program gets stuck while trying to read a file using read() system call

Here is my code snippet:
int fd;
bufsize = 30;
char buf[bufsize];
char cmd[100] = "file.txt";
int newfd = 1;
if (fd = open(cmd,O_RDONLY) >=0){
puts("wanna read");
while (read(fd,&bin_buf,bufsize)==1){
puts("reading");
write(newfd,&bin_buf,bufsize);
}
close(fd);
}
So here the program prints "wanna read" but never prints "reading". I have also tried opening using nonblock flag, but no use. Can anybody help me? I must use open() and read() system calls only. Thanks.
Edit: I have made some clarifications in the code. Actually the newfd that I'm writing to is a socket descriptor, but I don't think that is important for this problem because it sticks on the read which is before the write.
The first problem is your if statement. You forgot to use enough parentheses, so if the open() works, the read tries to read from file descriptor 1, aka standard output. If that's your terminal (it probably is) on a Unix box, then that works — surprising though that may be; the program is waiting for you to type something.
Fix: use parentheses!
if ((fd = open(cmd, O_RDONLY)) >= 0)
The assignment is done before, not after, the comparison.
I observe in passing that you don't show how you set cmd, but if you see the 'wanna read' message, it must be OK. You don't show how newfd is initialized; maybe that's 1 too.
You also have the issue with 'what the read() call returns'. You probably need:
int fd;
char buf[bufsize];
int newfd = 1;
if ((fd = open(cmd, O_RDONLY)) >= 0)
{
puts("wanna read");
int nbytes; // ssize_t if you prefer
while ((nbytes = read(fd, buf, sizeof(buf))) > 0)
{
puts("reading");
write(newfd, buf, nbytes);
}
close(fd);
}
You can demonstrate my primary observation by typing something ('Surprise', or 'Terminal file descriptors are often readable and writable' or something) with your original if but my loop body and then writing that somewhere.
Your read() call attempts to read bufsize bytes and returns the number of bytes actually read. Unless bufsize ==, it is quite unlikely read() will return 1, so the block is almost always skipped and nothing get written.
Also note that if (fd = open(cmd, O_RDONLY) >= 0) is incorrect and would set fd to 1, the handle for standard output, if the file exists, causing the read to fail as standard input is most likely not opened for reading.
Note that reading with the read system call is tricky on some environments, because a return value of -1 may be restartable.
Here is an improved version:
int catenate_file(const char *cmd, int newfd, size_t bufsize) {
int fd;
char buf[bufsize];
if ((fd = open(cmd, O_RDONLY)) >= 0) {
puts("wanna read");
ssize_t nc;
while ((nc = read(fd, buf, bufsize)) != 0) {
if (nc < 0) {
if (errno == EINTR)
continue;
else
break;
}
printf("read %zd bytes\n", nc);
write(newfd, buf, nc);
}
close(fd);
return 0;
}
return -1;
}
read returns the number of bytes read from file that can be bufsize or less if the remainder of the file that has to be read is shorter than bufsize.
In your case most probably bufsize is bigger than 1 and the file is bigger than 1 byte so the condition of the while loop is evaluated false, the code is skipped to the point where file is closed.
You should check if there if there are more bytes to be read:
while( read(fd,&bin_buf,bufsize) > 0 ) {

How to minimize the number of system calls? in C

How to minimize the number of system calls read() and write() in my code ?
int copy(char* entry, char* exit){
char buf;
int in;
int out;
in = open(entry,O_RDONLY);
out = open(exit ,O_APPEND|O_WRONLY);
while(read(in, &buf, 1) != 0){
write(out, &buf, 1); }
close(in);
close(out);
return 0;
}
Assuming you enlarge your buffer to for example 256, now write:
char buf[256];
int n;
...
while((n=read(in, buf, sizeof(buf))) > 0){
write(out, buf, n);
}
This reads, upon every read, a maximum of 256 bytes. read returns the number of bytes read, so n now has this number, which is what you write out. The last read will be less than 256, so the last write will also be less than 256.

Using read and write to do a server and a client (FTP protocol)

My code is too long to post all here so i'm going to sum up what's wrong.
In a server part i'm sending on a socket 3 things :
A message
The content of a file
Another message
In a client part i'm receiving these things but :
This first is to print on terminal
The second to write in a new file
The last to print on the terminal too
But my client is stuck on a read and i really don't know why. I'm on the problem for hour so if someone can help me, it will be very great !
edit : Basically, i think my problem is that i don't know what to write on the server to stop the read on the client.. Is it \n, \0.. ?
Here's the 2 part of code :
server
void send_content(t_server *s, FILE *fd, int rfd)
{
int len;
char *buff;
write(s->socket, "150 File status okay;" \
"about to open data connection.\n\0", strlen("150 File status okay;about to open data connection.\n\0"));
fseek(fd, 0, SEEK_END);
len = ftell(fd);
buff = malloc(len * sizeof(char));
read(rfd, buff, len);
write(s->socket, buff, len);
write(s->socket, "\n\0", strlen("\n\0"));
write(s->socket, "226 Closing data connection.\n\0", strlen("226 Closing data connection.\n\0"));
free(buff);
}
client
void getfile(t_client *c, char **tab)
{
int ret;
int fd;
int z;
char buff[4096];
z = 0;
read(c->fd, buff, 4096);
write(1, buff, strlen(buff));
if (strlen(buff) < 25)
return ;
fd = creat(tab[1], S_IRUSR | S_IWUSR);
while (z == 0 && (ret = read(c->fd, buff, 4096)) > 0)
{
if (ret < 4096)
z = -1;
write(fd, buff, strlen(buff));
memset(buff, '\0', 4096);
}
read(c->fd, buff, 4096); // Stuck here
write(1, buff, strlen(buff));
close(fd);
}
Like noted you need a read function like this to make sure you receive
specified number of bytes(this function will loop till it receives number of bytes it was told to). Just use this receivall method instead of read everywhere.
With files you typically first send the file length, and then receive the file.
I did something similar while ago, hope it will help you a bit. This is the client side, which tries to receive first file length from the server, then the file:
/* create file */
FILE * ptrMyFile = fopen(&filenames[i][0],"wb");
if(NULL == ptrMyFile)
{
printf("Unable to open file \n");
return 1;
}
int size = 0;
int t = 4;
/* first receive file size from server */
/* NOTE: error checking is omitted from code, nevertheless users should stil do some error checking when using this code */
readall(sockfd, (unsigned char*) &size, &t);
/* how many 256 byte chunks are there? */
int div = size / 256;
/* loop to receive each chunk. */
for(int k = 0; k < div; k++)
{
int chunk_size = 256;
/* make sure we receive 256 bytes */
readall(sockfd, buffer, &chunk_size);
/* write to file */
fwrite(buffer, chunk_size, 1, ptrMyFile);
}
/* read the final chunk. */
int whatsleft = size - 256 * div;
readall(sockfd, buffer, &whatsleft);
/* write */
fwrite(buffer, whatsleft, 1, ptrMyFile);
/* close file */
fclose(ptrMyFile);
I leave the server part to you.
char buff[4096];
z = 0;
read(c->fd, buff, 4096);
write(1, buff, strlen(buff));
You should be saving the return value of the call to read(), in order to find out how many bytes you just received. You may have to make several calls to read() in order to get the entire message. It's wrong to use strlen() to find out how many bytes were received, because the buffer contents are uninitialized, and the first chunk of the message could be cut off anywhere, so you can't count on it being null-terminated.

How to use read and write past BUFSIZ in C

For an assignment, I'm supposed to create two methods: Method one will read() and write() the input file to an empty output file, one byte at a time (slowly).
The other method will instead use char buf[BUFSIZ]; where BUFSIZ is from <stdio.h>. We are supposed to read() and write() with the BUFSIZ which will make things a lot faster.
The input file we test each method on is just a linux dictionary (/dict/linux.words).
I've correctly implemented method one, where I call read() and write() on one character at a time, copying the input file to the output file. Although it's very slow, it at least copies everything over.
My code for this looks like this:
// assume we have a valid, opened fd_in and fd_out file.
char buf;
while(read(fd_in, buf, 1) != 0)
write(fd_out, buf, 1);
For method two however, where I use BUFSIZ, I am not able to transfer every single entry into the output file. It fails in the z entries, and doesn't write anymore.
So, my first try:
// assume we have a valid, opened fd_in and fd_out file
char buf[BUFSIZ];
while(read(fd_in, buf, BUFSIZ) != 0)
write(fd_out, buf, BUFSIZ);
doesn't work.
I understand that read() will return either the number of bytes read or 0 if it is at the end of a file. The problem I'm having is understanding how I can compare read() to BUFSIZ, and then loop around and start read() at where it left off until I reach the real end of file.
Since your file will most likely not be an exact multiple of BUFSIZ you need to check for the actual number of bytes read, so that the last block will be written correctly, e.g.
char buf[BUFSIZ];
ssize_t n;
while((n = read(fd_in, buf, BUFSIZ)) > 0)
write(fd_out, buf, n);
this code:
// assume we have a valid, opened fd_in and fd_out file
char buf[BUFSIZ];
while(read(fd_in, buf, BUFSIZ) != 0)
write(fd_out, buf, BUFSIZ);
leaves much to be desired,
does not handle a short remaining char count at the end of the file,
does not handle errors, etc.
a much better code block would be:
// assume we have a valid, opened fd_in and fd_out file
char buf[BUFSIZ];
int readCount; // number of bytes read
int writeCount; // number of bytes written
while(1)
{
if( 0 > (readCount = read(fd_in, buf, BUFSIZ) ) )
{ // then, read failed
perror( "read failed" );
exit( EXIT_FAILURE );
}
// implied else, read successful
if( 0 == readCount )
{ // then assume end of file
break; // exit while loop
}
// implied else, readCount > 0
if( readCount != (writeCount = write( fd_out, buf, readCount ) ) )
{ // then, error occurred
perror( "write failed" );
exit( EXIT_FAILURE );
}
// implied else, write successful
} // end while
Note: I did not include the closing of input/output files statements
before each call to exit() however, that does need to be added

Short read on named pipes (matlab->linux)

I've got some code I'm writing that is expecting messages from a Matlab program via a named pipe, e.g., "/tmp/named_pipe_0". I can get pipes mkfifo and opened find, but when the C program goes to read() from the pipe, instead of the expected 5004 bytes, I'll get short values like 4096, 904, 5000, 4096, etc. I've already verified that Matlab is supposedly sending the correct 5004 bytes (at least, it's told to), so I'm wondering what the cause is. Anyone run across something like this before?
Matt
This is expected, a read on a pipe/socket/named pipe gives you back the data as soon as something is available.
If you need to read 5004 byte, you'd do it in a loop that appends you your own buffer up till you get that many bytes (or an error or eof occurs)
e.g.
size_t readn(int fd, void *buf, ssize_t len)
{
ssize_t tot = 0;
unsigned char *p = buf;
while (tot != len) {
ssize_t r = read(fd, p + tot, len - tot);
if (r == 0) //premature end of reading
break;
else if (r == -1) //error
return -1
tot += r;
}
return tot;
}
...
char buf[5004];
if (readn(pipe_fd, buf, sizeof buf) != sizeof buf) {
// something went bad
} else {
//got all the 5004 bytes
}

Resources