read
The function reads data from open devices or files.
# Include <unistd. h> ssize_t read (int fd, void * Buf, size_t count); Return Value: number of bytes read successfully. If an error occurs,-1 is returned and errno is set, if the end of the file has been reached before the read operation is called, 0 is returned for this read operation.
Parameterscount
The number of bytes requested to read. The read data is stored in the buffer zone.buf
. Note that the read/write location may be different from the read/write location when the C standard I/O library is used. This read/write location is recorded in the kernel, when the C standard I/O library is used, the read/write location is in the user space I/O buffer. For examplefgetc
Read one byte,fgetc
It is possible to pre-read 1024 bytes from the kernel to the I/O buffer, and then return the first byte. At this time, the read/write position recorded by the file in the kernel is 1024, whileFILE
The read/write position of the record in the struct is 1. Note that the return value type isssize_t
, Indicating signedsize_t
In this way, both the number of positive bytes and 0 (indicating that the object is reached) can be returned, and the negative value-1 (indicating an error) can be returned ).read
Description of the return value when the function returnsbuf
The first few bytes are just read. In some cases, the actual number of bytes read (returned value) is smaller than the number of bytes read by the request.count
For example:
When reading a regular filecount
Bytes have reached the end of the file. For example, if there are 30 bytes at the end of the file and 100 bytes are requested to be readread
Returns 30. next timeread
0 is returned.
Read from the terminal device, usually in the unit of action. If you read a line break, the system returns the result.
Read from the network. Based on different transport layer protocols and kernel caching mechanisms, the returned value may be smaller than the number of bytes requested. The socket programming section will explain in detail later.
write
The function writes data to an opened device or file.
# Include <unistd. h> ssize_t write (int fd, const void * Buf, size_t count); return value: the number of written bytes is returned successfully, error-1 is returned, and errno is set
When writing a regular file,write
The return value is usually equal to the number of bytes written by the request.count
But write to the terminal device or network is not necessarily.
Reading regular files is not blocked, no matter how many bytes are read,read
Will be returned within a limited period of time. Reading from the terminal device or network is not necessarily. If the data entered from the terminal does not have a line break, callread
The read terminal device is blocked. If no data packet is received on the network, callread
Reads from the network will be blocked. It is not clear how long it will be blocked. If no data has been reached, it will be blocked. Similarly, writing regular files will not be blocked, but writing to the terminal device or network is not necessarily.
Now let's clarify the concept of block. When a process calls a blocked system function, the process is put into sleep state. At this time, the kernel Schedules other processes to run, wait until the waiting event of the process occurs (for example, packets are received on the network, orsleep
The specified sleep time is reached. The running state is opposite to the sleeping state. In the Linux kernel, processes in the running state are divided into two situations:
Being scheduled. The CPU is in the context of the process, and the program counter (eip
The command address of the process is saved, and the intermediate result of the process operation is saved in the General Register. The command of the process is being executed, and the address space of the process is being read and written.
Ready. This process can be executed at any time without waiting for any event, but the CPU is still executing another process, so the process is waiting for scheduling by the kernel in a ready queue. There may be multiple ready processes in the system at the same time. Who should execute the scheduling? The scheduling algorithm of the kernel is based on priority and time slice, and the priority and time slice of each process are dynamically adjusted according to the running status of each process, so that every process can get a fair execution opportunity, at the same time, the user experience should be taken into account, and the response of processes that interact with users should not be too slow.
The following applet reads data from the terminal and then writes it back to the terminal.
Example 28.2. Blocking the read Terminal
#include <unistd.h>#include <stdlib.h>int main(void){char buf[10];int n;n = read(STDIN_FILENO, buf, 10);if (n < 0) {perror("read STDIN_FILENO");exit(1);}write(STDOUT_FILENO, buf, n);return 0;}
The execution result is as follows:
$./A. Out Hello (Press ENTER) Hello $./A. Out Hello World (Press ENTER) Hello worl $ dbash: D: Command not found
First executiona.out
The result is normal, and the second execution process is a bit special. Now let's analyze it:
Shell Process Creationa.out
Process,a.out
The process starts to run, while the shell process waits for sleep.a.out
The process exits.
a.out
Callread
Wait until the terminal device enters a line break.read
Return,read
Read-Only takes 10 characters, and the remaining characters are still stored in the input buffer of the kernel terminal device.
a.out
The process prints and exits. At this time, the shell process resumes operation. The shell continues to read the user-input commands from the terminal, so it reads the remaining characters D and line breaks in the input buffer zone of the terminal device, it is interpreted and executed as a command, and the result shows that the command cannot be executed, without D.
Ifopen
A device is specifiedO_NONBLOCK
Flag,read
/write
It will not be blocked. Toread
For example, if the device is not readable,-1 is returned.errno
IsEWOULDBLOCK
(OrEAGAIN
These two macros have the same defined values), indicating that they should be blocked here (wowould
Block, virtual tone), in fact, it does not block but directly returns an error, the caller should try to read again (again ). This kind of behavior is called poll. The caller only queries it, instead of blocking it, so that the caller can monitor multiple devices at the same time:
While (1) {non-blocking read (device 1); If (device 1 has data arrival) processing data; non-blocking read (device 2); If (device 2 has data arrival) process data ;...}
IfRead (device 1)
Is blocked, so as long as device 1 does not have data to arrive, it will always be blocked on device 1read
In call, even if device 2 has data arriving, it cannot be processed. Using non-blocking I/O can prevent device 2 from being processed in a timely manner.
Non-blocking I/O has a drawback. If no data has been reached for all devices, the caller needs to perform repeated queries for useless work. If the congestion exists, the operating system can schedule other processes for execution, it won't be useless. When using non-blocking I/Owhile
In the loop, the query is continuously performed (this is called the tight loop), but the query is delayed for a while to avoid too much useless work. Other processes can be scheduled for execution when the wait is delayed.
While (1) {non-blocking read (device 1); If (device 1 has data arrival) processing data; non-blocking read (device 2); If (device 2 has data arrival) processing data ;... sleep (n );}
The problem is that device 1 may not be able to process data in a timely manner when it arrives. It takes up to n seconds to process the data, and repeated queries are still useless. To learn laterselect(2)
The function can monitor multiple devices at the same time in a blocking manner, and can set the timeout time for blocking wait to solve this problem satisfactorily.
The following is an example of non-blocking I/O. Currently, we have learned that only terminals can cause blocking, so we use terminals for this experiment. When the program starts to run, the files automatically opened on file descriptors 0, 1, and 2 are terminals, but noO_NONBLOCK
Flag. So, just like 28.2 "blocking read terminals", standard read input is blocked. We can re-open the Device File/dev/tty
(Indicates the current terminal ).O_NONBLOCK
Flag.
Example 28.3. Non-blocking read Terminal
#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <string.h>#include <stdlib.h>#define MSG_TRY "try again\n"int main(void){char buf[10];int fd, n;fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);if(fd<0) {perror("open /dev/tty");exit(1);}tryagain:n = read(fd, buf, 10);if (n < 0) {if (errno == EAGAIN) {sleep(1);write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));goto tryagain;}perror("read /dev/tty");exit(1);}write(STDOUT_FILENO, buf, n);close(fd);return 0;}
The following is an example of non-blocking I/O timeout. It not only ensures the logic of timeout and exit, but also ensures that the processing delay is small when data arrives.
Example 28.4. Non-blocking read terminal and wait timeout
#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <string.h>#include <stdlib.h>#define MSG_TRY "try again\n"#define MSG_TIMEOUT "timeout\n"int main(void){char buf[10];int fd, n, i;fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);if(fd<0) {perror("open /dev/tty");exit(1);}for(i=0; i<5; i++) {n = read(fd, buf, 10);if(n>=0)break;if(errno!=EAGAIN) {perror("read /dev/tty");exit(1);}sleep(1);write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));}if(i==5)write(STDOUT_FILENO, MSG_TIMEOUT, strlen(MSG_TIMEOUT));elsewrite(STDOUT_FILENO, buf, n);close(fd);return 0;}