Linux 网络编程中的read和write函数正确的使用方式

  • Post author:
  • Post category:linux


字节流套接字上的read和write函数所表现的行为不同于通常的文件IO,字节流套接字上调用read和write输入或输出的可能比请求的数量少,然而这不是出错的状态,例如某个中端使read和write提前返回,这时就应该继续读和写而不是出错返回了,下面是unp中对read和write函数在socket中的使用的封装。

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
ssize_t readn(int fd,void* buff,size_t nbytes){
    ssize_t nleft;
    ssize_t nread;
    char* ptr;

    nleft=(ssize_t)nbytes;
    ptr=(char*)buff;
    nread=0;
    while(nleft>0){
        if((nread=read(fd,ptr,nleft))<0){
            if(errno==EINTR){
                nread=0;
            }
            else{
                return -1;
            }
        }
        else if(nread==0){  //read返回0代表读到EOF
            break;
        }
        else{
            nleft-=nread;
            ptr+=nread;
        }
    }
    return (nbytes-nread);
}

ssize_t writen(int fd,void* buff,size_t nbytes){
    ssize_t nleft;
    ssize_t nwrite;
    char* ptr;

    nleft=(ssize_t)nbytes;
    nwrite=0;
    ptr=(char*)buff;

    while(nleft>0){
        if((nwrite=write(fd,ptr,nleft))<=0){  //write返回0代表出错
            if(nwrite<0&&errno==EINTR){
                nwrite=0;
            }
            else{
                return -1;
            }
        }
        else{
            nleft-=nwrite;
            ptr+=nwrite;
        }
    }
    return (nbytes);
}
//频繁使用read函数这个效率非常低
ssize_t readline(int fd,void* buff,size_t nbytes){
    ssize_t n,rc;
    char c,*ptr;

    ptr=(char*)buff;
    for(n=1;n<nbytes;++n){
    again:
        if((rc=read(fd,&c,1))==1){
            *ptr++=c;
            if(c=='\n')
                break;
        }
        else if(rc==0)
            return(n-1);
        else{
            if(errno==EINTR){
                goto again;
            }
            return -1;
        }

    }
    return (n);
}

//下面是一个改进版的但是这个版本使用了static变量,它是线程不安全的
#define MAXLINE 4096
static int read_cnt;
static char* read_ptr;
static char read_buf[MAXLINE];
//先从内核读一些数据到用户空间,在每次都从用户空间中读数据
static ssize_t myread(int fd,char* ptr){
    if(read_cnt<=0){
    again:
        if((read_cnt=read(fd,read_buf,sizeof(read_buf)))<0){
                if(errno==EINTR)
                    goto again;
                return -1;
        }
        else if(read_cnt==0)
            return 0;
        else
            read_ptr=read_buf;
    }
    read_cnt--;
    *ptr=*read_ptr++;
    return 1;
}

ssize_t readline(int fd,void* buff,size_t maxlen){
    ssize_t n,rc;
    char c,*ptr;
    ptr=(char*)buff;
    for(n=1;n<maxlen;++n){
        if((rc=myread(fd,&c))==1){
            *ptr++=c;
            if(c=='\n')
                break;
        }
        else if(rc==0){
            *ptr='\0';
            return (n-1);
        }
        else{
            return -1;
        }

    }
    *ptr='\0';
    return n;
}

ssize_t readlinebuf(void **vptrtptr){
    if(read_cnt)
        *vptrvptr=read_ptr;
    
    return read_cnt;
}

转载于:https://www.cnblogs.com/CodingUniversal/p/7597841.html