zoukankan      html  css  js  c++  java
  • Linux 网络编程中的read和write函数正确的使用方式

    字节流套接字上的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=='
    ')
                    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=='
    ')
                    break;
            }
            else if(rc==0){
                *ptr='';
                return (n-1);
            }
            else{
                return -1;
            }
    
        }
        *ptr='';
        return n;
    }
    
    ssize_t readlinebuf(void **vptrtptr){
        if(read_cnt)
            *vptrvptr=read_ptr;
        
        return read_cnt;
    }
    
    
  • 相关阅读:
    #pragma
    I/0概念介绍
    Android Eclipse 源码工程 调试
    SHELL四则运算和比较
    Android源码中添加 修改应用
    android ubuntu9.10 源码的编译 Eclipse工程 Contacts编译 应用加载
    【Wonder原创】LogMiner使用实践
    【转】Oracle入门教程,新手必读
    【Wonder原创】关于MSSQL通过DBLink访问Oracle问题
    【杂记】SQLServer
  • 原文地址:https://www.cnblogs.com/CodingUniversal/p/7597841.html
Copyright © 2011-2022 走看看