read() and write() non text files in chunks in C - c

I have a client server program in which i read the file from the server to the client in chunks, over TCP. However, not all chunks being sent are of the size I have given. Some of them are less than the requested size or even 1.
This is my server side code for reading from the file and writing to socket
rd=read(filed, buffer,128);
write(socketd,buffer,128);
This true for only non text files. On using a txt file, it works perfectly, but fails for pdfs, ppts, images. Is there any way to read these non text files in chunks?
Sample of size in bytes being read in each iteration for a pdf file
128
128
128
128
116
128
128
36

You should only write the amount that was actually read from the file. If the size of the file isn't a multiple of 128, then the last read can't return 128 bytes, it just returns what's left in the file. Use rd as the amount to write to the socket.
while ((rd = read(filed, buffer, 128)) > 0) {
write(socketd, buffer, rd);
}

Issue resolved. I was using strlen(buffer) which gave those numbers. The integer returned by read() was 128, as desired.

Related

Reading from Socket in a loop?

I am creating a server/client TCP in C.
The idea is for the server to send a relatively large amount of information. However, the buffer in the client has a size of only 512 (I don't want to increase this size), and obviously, the information sent by the server is larger than this. Let's imagine 812 bytes.
What I want to do is, in the client, read 512 bytes, print them on the client's console, and then read the remaining bytes, and print them as well.
Here's what should happen:
1) Create server, and block in the read() system call (waiting for the client to write something);
2) Create the client, and write something in the socket, and then blocks on read(), waiting for the server to respond;
3) The server's read() call returns, and now server has to send that large amount of data, using the following code (after creating a new process):
dup2(new_socketfd, STDOUT_FILENO); // Redirect to socket
execlp("/application", "application", NULL); // Application that prints the information to send to the client
Let's imagine "application" printed 812 bytes of data to the socket.
4) Now the client has to read 812 bytes, with a buffer size of 512. That's my problem.
How can I approach this problem? I was wondering if I could make a loop, and read until there's nothing to read, 512 by 512 bytes. But as soon as there's nothing to read, client will block on read().
Any ideas?
recv will block when there is no data in the stream. Any data extracted from the stream, the length is returned from recv.
You can write a simple function to extract the full data just by using an offset variable and checking the return value.
A simple function like this will do.
ssize_t readfull(int descriptor,char* buffer, ssize_t sizetoread){
ssize_t offset = 0;
while (offset <sizetoread) {
ssize_t read = recv(descriptor,buffer+offset,sizetoread-offset,0);
if(read < 1){
return offset;
}
offset+=read;
}
return offset;
}
Also servers typically send some kind of EOF when the data is finished. Either the server might first send the length of the message to be read which is a constant size either four or eight bytes, then it sends the data so you know ahead of time how much to read. Or, in the case of HTTP for example, there is the content-length field as well as the '\r\n' delimeters.
Realistically there is no way to know how much data the server has available to send you, it's impractical. The server has to tell you how much data there is through some kind of indicator.
Since you're writing the server yourself, you can first send a four byte message which can be an int value of how much data the client should read.
So your server can look like this:
int sizetosend = arbitrarysize;
send(descriptor,(char*)&sizetosend,sizeof(int),0);
send(descriptor,buffer,sizetosend,0);
Then on your client side, read four bytes then the buffer.
int sizetoread = 0;
ssize_t read = recv(descriptor,(char*)&sizetoread,sizeof(int),0);
if(read < 4)
return;
//Now just follow the code I posted above

socket read()'s byte offset (linux)

When we use read() function with file descriptor(not socket), it has byte-offset like this.
read(file descriptor, message1, 20);
read(file descriptor, message2, 40);
After number1 command, the file descriptor's byte offset is 20 as it says.
Then, number 2 command read the file at the byte offset 20, and the file descriptor's final offset is 60 now.
So, now my question is about socket. Let me explain you situations.
On server-client model, client sends server 100 bytes(lets assum it's string data). But, unfortunately, server receive data sequentially 10, 20, 70(not 100 bytes at once.)
So, because of this situation, server source code is like this.
51 while(recv_len<100)
52 {
53 recv_count=read(cli_sock, message[recv_len], 1024);
54
55 if(recv_count==-1)
56 error_handling("read() error");
57
58 recv_len+=recv_count;
59 }
So client writes 10 bytes data one of 100 bytes string to server, at first.
Anyway, server execute read() function, and reads 1024 bytes. So, the server takes 10 bytes. But, its byte-offset is 1024 now.
So, after client's second data(20 bytes data), server must read at byte offset 1024. Then, how can server reads 20 bytes which is sent from client? I mean originally, server must read 20 bytes at byte offset 10(not 1024), because 10 bytes data had sent before 20bytes. But, server is at byte offset 1024. How this can be possible?
This
recv_count=read(cli_sock, message[recv_len], 1024);
will not do what you think.
It should be :
recv_count=read(cli_sock, message + recv_len, 1024 - recv_len);
or
recv_count=read(cli_sock, &message[recv_len], 1024 - recv_len);
read the man page and if don't understand something, don't hesitate to ask for precision (even thought that blue112 already explain it all).
You've got it wrong. The third parameter of a read() call isn't an offset, it represents the number of bytes you want to read, at max.
The actual number read is returned by the read() call.
Look here : http://man7.org/linux/man-pages/man2/read.2.html
Also, you should pass a pointer to read() calls.
So message[recv_len] isn't gonna do. You're looking for message + recv_len

Random seek on CD-ROM drive

This works on Linux, but not (as I would like) on FreeBSD:
I wish to exercise my CD-ROM drive, to keep the dust off the lens. On Linux I run (as root) a C program I wrote which seeks back and forth, reading a single block each time as it goes. On FreeBSD this program doesn't get too far. I can open the device and seek to (say) block 1. But when I try to read the block, I get error 22 (EINVAL). It fails on the first read, at block 1, whether or not the device is mounted (-t cd9660). How do I proceed?
Full program is here. The relevant snippet:
lo_fd=Open(ar_argv[1],
O_RDONLY,
0
);
lo_high_bit=1;
while(lo_high_bit>0)
{
if(lseek(lo_fd,
lo_high_bit,
SEEK_SET
)
==
(off_t)-1
)
{
lo_high_bit>>=1;
break;
}
if(read(lo_fd,
lo_buffer,
1
)
!=
1
)
{
lo_high_bit>>=1;
break;
}
lo_high_bit<<=1;
}
It turns out that I was making two errors: trying to read a byte at a time, and lseek()ing to byte 1. fstat() on the device shows st_blksize of 4096.
Seeking to 4096 and reading 4096 bytes works.
Seeking to 2048 and reading 2048 bytes works.
Seeking to 2048 and reading 1024 bytes gives EINVAL on the read().
Seeking to 1024 and reading 2048 bytes gives EINVAL on the read().

Counting bytes received by posix read()

I get confused with one line of code:
temp_uart_count = read(VCOM, temp_uart_data, 4096);
I found more about read function at http://linux.die.net/man/3/read, but if everything is okay it returns 0, so how we can get num of bytes received from that?
temp_uart_count is used to count how much bytes we received from virtual COM port and stored it to temp_uart_data which is 4096 bytes wide.
Am I really getting how much bytes i received with this line of code?
... but if everything is okay it returns 0, so how we can get num of bytes received from that?
A return code of zero simply means that read() was unable to provide any data.
Am I really getting how much bytes i received with this line of code?
Yes, a positive return code (i.e. >= 0) from read() is an accurate count of bytes that were returned in the buffer. Zero is a valid count.
If you're expecting more data, then simply repeat the read() syscall. (However you may have setup the termios arguments poorly, e.g. VMIN=0 and VTIME=0).
And - zero indicates end of file
If you get 0, it means that the end of file (or an equivalent condition) has been reached and there is nothing else to read.
The above (one from a comment, and the other in an answer) are incorrect.
Reading from a tty device (e.g. a serial port) is not like reading from a file on a block device, but is temporal. Data for reading is only available as it is received over the comm link.
A non-blocking read() will return with -1 and errno set to EAGAIN when there is no data available.
A blocking non-canonical read() will return zero when there is no data available. Correlate your termios configuration with this to confirm that a return of zero is valid (and does not indicate "end of file").
In either case, the read() can be repeated to get more data when/if it arrives.
Also when using non-canonical (aka raw) mode (or non-blocking reads), do not expect or rely on the the read() to perform message or packet management for you. You will need to add a layer to your program to read bytes, concatenate those bytes into a complete message datagram/packet, and validate it before that message can be processed.
ssize_t read(int fd, void *buf, size_t count); returns you the size of bytes he read and stores it into the value you passed in parameters. And when errors happen it returns -1 (with errno set to EINTR) or to return the number of bytes already read..
From the linux man :
On files that support seeking, the read operation commences at the current file offset, and the file offset is incremented by the number of bytes read. If the current file offset is at or past the end of file, no bytes are read, and read() returns zero.
Yes, temp_uart_count will contain the actual number of bytes read, and obviously that number will be smaller or equal to the number of elements of temp_uart_data. If you get 0, it means that the end of file (or an equivalent condition) has been reached and there is nothing else to read.
If it returns -1 this indicate that an error has occurred and you'll need to check the errno variable to understand what happened.

C & Linux: Waiting for when a file has been written to

I'm currently working on a project that will read data from a micro-controller via serial communications.
As of right now, the program (on my computer), opens a /dev/tty* file and is able to read/write to it. The micro-controller will send a packet of n bytes at any time. I want to know if there is any way I can tell when all of the bytes have been written to the file?
I've been looking at the select() and poll() functions, but they seem to be only able to tell when a byte is ready, but not when every byte has been written.
Any help is appreciated. Thanks!
If your n is hardcoded you can just do (with pseudocode):
received_data = offset_from_last_round
while( received_data < n )
{
use select() for waiting data to arrive
read() all data you can, dont forget to check buffer oveflow here
received_data += how much data was red
}
full_message = buffer[ 0 ... N - 1 ]
offset_to_next_round = buffer[ N .. received_data ]
If n is not hardcoded you need to do something like what #Golgauth suggested, or add some "end of transmission" sequence/byte to your message (which is tricky if you have binary file/data to transmit). In short: You need some sort of protocol.
Well, the idea is that your binary file should start by some bytes which actually give the size that has to be read next.
Read N bytes => gives the DATASIZE, i.e. how many bytes remaining: (FILESIZE - N)
Read (DATASIZE) bytes => gives the data themselves (readable by blocks/packets of size n)
This is the kind of discussion we were having here actually (this about how to interpret a raw PCM wav sound file, but this is the same point: getting the number N of samples, to determine how many blocks are to be read next to get the file with concern to the integrity).

Resources