read函数(man2)的返回值有什么含义?(当然没这么简单,请说出read用于设备文件,普通文件和套接字时候的返回值含义,套接字区分阻塞型和非阻塞型)
By 崔姣姣
在文件那一章我们用到了read函数,它可以读取设备文件和普通文件中的数据,同时在网络编程中也会用到该函数,读取来自socket的数据。
ssize_t read(int fd, void *buf, size_t nbytes);
先说一下各参数的含义:参数fd,是文件描述符;参数buf用来存放读到的数据内容,(void *)表示通用指针(看一些开源代码的话会经常碰见);参数nbytes是请求读取的字节数。
还有就是返回值问题:read函数总共会有三种返回值情况,A.若成功,返回读到的字节数;B.若已到文件尾或无可读取的数据,返回0;C.若出错,返回-1.(文件的读写位置会随读取到的字节移动,读写位置记录在内核中)
曾经听过一句话:linux下,一切设备皆文件。虽然是这样说,但肯定有不同的地方我坚信,现在先不讨论这个。read函数是一个不带缓存的文件I/O操作函数,与此同时open,close,write等也是。
当读操作完成以后,文件的读写位置会向后移动,移动的长度就是读取的字节数,下次读操作将从新的读写位置开始。值得注意的是:如果在到达文件尾之前有30个字节,而要求读100个字节,则read返回30个字节。当下一次再调用read时,它将返回0(文件尾端)(摘自APUE)。我们常用的是从一个普通文件中获得相应的数据,当read返回值count <=nbytes(相应的读到数据的字节数),下次调用read时若返回count = 0;则说明文件中的数据读写完毕。
以终端这一设备文件来讲,通常一次读一行,读到换行时返回。
举个栗子:
char buf[10];
n = read(STDIN_FILENO, buf, 10);
从设备中只读10个字节,调用read时睡眠等待,直到终端设备输入换行才从read返回,read只读走10个字符,剩下的字符仍然保存在内核终端设备输入缓冲区中,而read返回的是只读走的字节数。这就很好地解释了下面这种情况:
输入:Hello\n 输出:Hello 此时n = 6;
输入:Hello Linux 输出:Hello
Linu 此时n = 10 ;很明显buf空间不够,MAN = 10, 所以n = 10;结果一目了然。
socket使用read返回值的含义与上面所提及的两种稍有不同的含义。
若对方结束了连接,则返回0;在read的过程中,如果信号被中断,若已经读取了一部分数据,则返回已读取的字节数;若没有读取,则返回-1,且error为EINTR。
A.对于阻塞的socket,当socket的接受缓冲区中没有数据时,read会一直阻塞住,等待返回直到有数据到来才返回。(可以联系线程同步现象)不管socket缓冲区中的数据量大于、等于或小于期望读取的数据量,都会返回其实际读取的数据长度。
B.对于非阻塞socket而言,不管socket的接受缓冲区中是否有数据,read都会立刻返回。返回情况与阻塞socket类似;
一般来说,读字符终端、网络的soket描述符、管道文件等,这些文件的缺省read都是阻塞的方式,如果是读磁盘上的文件,一般不会是阻塞方式。即使用锁和fcntl设置取消文件O_NOBLOCK状态,也会产生阻塞的read效果。
这篇博文纯属自己对read返回值的理解,有不到位的大方希望大家指出,谢谢!