封装非阻塞模式下的read,write函数

在非阻塞模式下当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;
}

 


 

你可能感兴趣的:(网络,buffer)