1,read 原型,参数以及返回值。
#include <uinstd.h>
ssize_t read(int fd, void *buf, size_t nbytes);
-----read,只是将内核中缓冲区的数据搬到用户进程空间。
参数:
fd:某个连接的套接字。
buf:从内核缓冲区读入的数据放到用户缓冲区的地址。
nbytes:希望读入的数据大小,一般不是真正读人的大小。
返回值:实际读取的长度。
-1:error会被置为相应的值。
error:为EAGAIN,表示在非阻塞下,此时无数据到达,立即返回。
error:为EINTR,表示被信号中断了。
0:对端已关闭,本端也需要close 该套接字。
>0:实际读取的数据长度。
2,read 阻塞和非阻塞下的区别:
- 阻塞下
原则是在不超过指定的长度下,有多少读多少,没有数据则一直等待,有可能会被信号中断。
比如,对端write写了10字节,本端read 读20字节,则此时read 直接返回,不用等待数据到达20字节后再返回,返回的长度是10字节。
- 非阻塞
没有数据的话,返回-1,并置相应的error;有数据的话直接返回读入的数据大小,不超过指定的长度。
比如,对端write写了10字节,本端read 只读5字节,则此时read 端返回5字节,剩下的5字节需要下次再读入,这种情况下需要循环读入。
3,read 循环读。
int nread(int fd, char *buf, int nbytes)
{
int len = 0;
int left = nbytes;
char *ptr = buf;
while(left)
{
len = read(fd, ptr, left);
if(len == -1)
{
if(error == EAGAIN)
len = 0;
}
if(len == 0)
{
close(fd);
break;
}
left -= len;
ptr += len;
}
return nbytes;
}
4,为什么read 不能一次性读完,需要循环来读?
当fd为管道或socket时,对方数据多次发送或网络延时较大时,一次read 都可能只读到部分数据。(因为tcp是面向字节流的)
5,总结
read | 阻塞下 | 非阻塞 |
无数据 | 一直等待 | 立马返回-1,error置为EAGAIN |
有数据 | 返回数据的大小(不超过指定的读入大小) | 返回数据的大小(不超过指定的读入大小) |