在非阻塞模式下当read读完fd中所有内容后将返回-1,并且errno设置为EAGAIN
read函数说明
read()会把参数fd 所指的文件传送count个字节到buf指针所指的内存中。
若参数count为0,则read为实际读取到的字节数,
如果返回0,表示已到达文件尾或是无可读取的数据
但在O_NONBLOCK模式下,无数据将返回-1
EINTR 此调用被信号所中断。
EAGAIN 当使用不可阻断I/O 时(O_NONBLOCK),若无数据可读取则返回此值。(这个就是为什么使用自己写的read函数出错原因)
自己改进的封装函数
int my_read(int fd, char *buf, int count)
{
int nread = 0;
int totlen = 0;
while(totlen != count)
{
nread = read(fd, buf, count - totlen);
if(nread < 0)
{
if(errno == EAGAIN)
{
return totlen;
}
else if(errno == EINTR)
{
nread = 0;
}
else
{
return -1;
}
}
else if(nread == 0)
{
return totlen;
}
totlen += nread;
buf += nread;
}
return totlen;
}
分析原因:
封装的read
调用Read(fd, buf, sizeof(buf)), 一般这个sizeof(buf)都比较大
int Read(int fd, char *buf, int count) {
int nread, totlen = 0;
while (totlen != count) {
nread = read(fd, buf, count - totlen);
if (nread == 0)
return totlen;
if (nread == -1)
return -1;
totlen += nread;
buf += nread;
}
return totlen;
}
fd设置的是O_NONBLOCK,第二次循环时无数据可读,nread返回-1, 结果函数执行失败
网上一般的封装函数
ssize_t read(int fd,void *buf,size_t nbyte)
read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数,如果返回的值是0 表示已经读到文件的结束了,
小于0表示出现了错误.如果错误为EINTR说明读是由中断引起的, 如果是ECONNREST表示网络连接出了问题.
ssize_t my_read(int fd, char *buffer, int length)
{
int bytes_left;
int bytes_read;
char *ptr;
ptr = buff;
bytes_left=length;
while(bytes_left>0)
{
bytes_read=read(fd, ptr, bytes_read);
if(bytes_read<0)
{
if(errno==EINTR)
bytes_read=0;
else
return(-1);
}
else if(bytes_read==0)
break;
bytes_left-=bytes_read;
ptr+=bytes_read;
}
return(length-bytes_left);
}
道理类似,但也没有处理O_NONBLOCK这种情况
另外常用的设置非阻塞模式函数
int setnonblock(int fd)
{
int flags;
flags = fcntl(fd, F_GETFL);
if(flags < 0)
{
return flags;
}
flags |= O_NONBLOCK;
if(fcntl(fd, F_SETFL, flags) < 0)
{
return -1;
}
return 0;
}
封装性不是很好,还是APUE的比较给力
static int set_fl(int fd, int flags)
{
int val;
val = fcntl(fd, F_GETFL, 0);
if(val < 0){
perror("fcntl get error");
exit(1);
}
val |= flags;
if(fcntl(fd, F_SETFL, val) < 0){
perror("fcntl set error");
exit(2);
}
return 0;
}
static int clr_fl(int fd, int flags)
{
int val;
val = fcntl(fd, F_GETFL, 0);
if(val < 0){
perror("fcntl get error");
exit(3);
}
val &= ~flags;
if(fcntl(fd, F_SETFL, val) < 0){
perror("fcntl clr error");
exit(4);
}
return 0;
}