C/C++编程:ACL_VSTREAM的写操作对比

1059 篇文章 286 订阅

向套接字写数据

   int acl_socket::acl_socket_writev(const struct iovec *vec, int count, int timeout){
        int ret;

        ret = (int) write(sock_, vec, count);
        if (ret > 0) {
            return ret;
        }

        if (timeout <= 0) {
            return ret;
        }



        if (errno != EWOULDBLOCK && errno != EAGAIN) {
            return ret;
        }

        if (this->acl_write_wait(timeout) < 0) {
            return -1;
        }

        ret = writev(sock_, vec, count);

        return ret;
        
    }
    int acl_socket::acl_socket_write(const void *buf, size_t size, int timeout)
    {
        int ret;

        ret = (int) write(sock_, buf, size);
        if (ret > 0) {
            return ret;
        }

        if (timeout <= 0) {
            return ret;
        }



        if (errno != EWOULDBLOCK && errno != EAGAIN) {
            return ret;
        }

        if (this->acl_write_wait(timeout) < 0) {
            return -1;
        }

        ret = write(sock_, buf, size);

        return ret;
    }

编程技巧: EINVAL错误时反复读取N次

    int ACL_VSTREAM::write_once(const void *vptr, int dlen)
    {
        int   n, neintr = 0;

        if (vptr == NULL || dlen <= 0) {
            logger_error("%s(%d), %s: vptr %s, dlen %d (<=0)", __FILE__,
                   __LINE__, __FUNCTION__, vptr ? "not null" : "null", (int) dlen);
            errnum_ = EINVAL;
            return ACL_VSTREAM_EOF;
        }

        if(type_ == ACL_VSTREAM_TYPE_FILE){
            logger_error("%s, %s(%d): ftype invalid",
                         __FUNCTION__, __FILE__, __LINE__);
            errnum_ = EINVAL;
            return ACL_VSTREAM_EOF;
        }

        if (fd_.socket_->get_socket() == ACL_SOCKET_INVALID) {
            logger_error("%s, %s(%d): sockfd invalid",
                   __FUNCTION__, __FILE__, __LINE__);
            errnum_ = EINVAL;
            return ACL_VSTREAM_EOF;
        }

TAG_AGAIN:

        /* 清除系统错误号 */
        errno = 0;

        n = fd_.socket_->acl_socket_write(vptr, dlen,rw_timeout_);

        if (n > 0) {
            total_write_cnt_ += n;
            return n;
        }

        errnum_ = errno;
        if (errnum_ == EINVAL) {
            if (++neintr >= 5) {
                flag_enable(ACL_VSTREAM_FLAG_ERR);
                return ACL_VSTREAM_EOF;
            }

            goto TAG_AGAIN;
        }

        if (errnum_ == EWOULDBLOCK || errnum_ == EAGAIN) {
            errno = EAGAIN;
        } else if (errnum_  == ETIMEDOUT) {
            flag_enable(ACL_VSTREAM_FLAG_TIMEOUT);
        } else {
            flag_enable(ACL_VSTREAM_FLAG_ERR);
        }

        return ACL_VSTREAM_EOF;
    }

    int ACL_VSTREAM::writev_once(const struct iovec *vec, int count){
        int   n, neintr = 0;

        if (vec == NULL || count <= 0) {
            logger_error("%s(%d), %s: vptr %s, dlen %d (<=0)", __FILE__,
                         __LINE__, __FUNCTION__, vec ? "not null" : "null", (int) count);
            errnum_ = EINVAL;
            return ACL_VSTREAM_EOF;
        }

        if(type_ == ACL_VSTREAM_TYPE_FILE){
            logger_error("%s, %s(%d): ftype invalid",
                         __FUNCTION__, __FILE__, __LINE__);
            errnum_ = EINVAL;
            return ACL_VSTREAM_EOF;
        }

        if (fd_.socket_->get_socket() == ACL_SOCKET_INVALID) {
            logger_error("%s, %s(%d): sockfd invalid",
                         __FUNCTION__, __FILE__, __LINE__);
            errnum_ = EINVAL;
            return ACL_VSTREAM_EOF;
        }

        TAG_AGAIN:

        /* 清除系统错误号 */
        errno = 0;

        n = fd_.socket_->acl_socket_writev(vec, count ,rw_timeout_);

        if (n > 0) {
            total_write_cnt_ += n;
            return n;
        }

        errnum_ = errno;
        if (errnum_ == EINVAL) {
            if (++neintr >= 5) {
                flag_enable(ACL_VSTREAM_FLAG_ERR);
                return ACL_VSTREAM_EOF;
            }

            goto TAG_AGAIN;
        }

        if (errnum_ == EWOULDBLOCK || errnum_ == EAGAIN) {
            errno = EAGAIN;
        } else if (errnum_  == ETIMEDOUT) {
            flag_enable(ACL_VSTREAM_FLAG_TIMEOUT);
        } else {
            flag_enable(ACL_VSTREAM_FLAG_ERR);
        }
        
        return ACL_VSTREAM_EOF;
    }

一次写入&&反复写

 int ACL_VSTREAM::write_once(const void *vptr, int dlen)
    {
        int   n, neintr = 0;

        if (vptr == NULL || dlen <= 0) {
            if (vptr == NULL) {
                printf("[error] %s, %s(%d): vptr null",
                       __FUNCTION__, __FILE__, __LINE__);
            }
            if (dlen <= 0) {
                printf("[error] %s, %s(%d): dlen(%d) <= 0",
                       __FUNCTION__, __FILE__, __LINE__, dlen);
            }
            errnum_ = EINVAL;
            return ACL_VSTREAM_EOF;
        }

        if (fd_.socket_->get_socket() == ACL_SOCKET_INVALID) {
            printf("[error] %s, %s(%d): sockfd invalid",
                   __FUNCTION__, __FILE__, __LINE__);
            errnum_ = EINVAL;
            return ACL_VSTREAM_EOF;
        }

TAG_AGAIN:

        /* 清除系统错误号 */
        errno = 0;


        
        n = fd_.socket_->acl_socket_write(vptr, dlen,0);

        if (n > 0) {
            total_write_cnt_ += n;
            return n;
        }

        errnum_ = errno;
        if (errnum_ == EINVAL) {
            if (++neintr >= 5) {
                flag_enable(ACL_VSTREAM_FLAG_ERR);
                return ACL_VSTREAM_EOF;
            }

            goto TAG_AGAIN;
        }

        if (errnum_ == EWOULDBLOCK) {
            errno = EAGAIN;
        } else if (errnum_  == ETIMEDOUT) {
            flag_enable(ACL_VSTREAM_FLAG_TIMEOUT);
        } else {
            flag_enable(ACL_VSTREAM_FLAG_ERR);
        }

        return ACL_VSTREAM_EOF;
    }



int ACL_VSTREAM::loop_writen(const void *vptr, size_t size)
    {
        const unsigned char *ptr = (const unsigned char *) vptr;
        int   once_dlen = 64 * 1024 * 1024;  /* xxx: 以 64KB 为单位写 */
        int   nleft = (int) size, n, len;

        while (nleft > 0) {
            len = nleft > once_dlen ? once_dlen : nleft;
            n = write_once(ptr, len);
            if (n < 0)
                return ACL_VSTREAM_EOF;

            nleft -= n;
            ptr   += n;
        }

        return (int) (ptr - (const unsigned char *) vptr);
    }

刷新写缓冲区中的数据

/**
     * 刷新写缓冲区里的数据
     * @return 刷新写缓冲区里的数据量或出错
     */
    int ACL_VSTREAM::acl_vstream_fflush(){
        if (wbuf_ == NULL || wbuf_dlen_ <= 0) {
            return 0;
        }

			// 反复将当前写缓冲区的数据写出
        int n = loop_writen(wbuf_, wbuf_dlen_);
        if (n > 0) {
            wbuf_dlen_ -= n;
            if(wbuf_dlen_ < 0){
                logger_fatal("%s(%d): wbuf_dlen(%d) < 0",
                             __FUNCTION__, __LINE__, wbuf_dlen_);
            }
        }else if(errnum_ != EAGAIN && errnum_ != EWOULDBLOCK){
            wbuf_dlen_ = 0;
        }

        return n;
    }

acl_vstream_write VS acl_vstream_writen

  • acl_vstream_writen是反复调用write_once直到写完或者出错。
  • acl_vstream_write只调用一次write_once,只写一次
    /**
          * 一次性写入流操作, 返回实际写入的字节数.
          * @param fp {ACL_VSTREAM*} 数据流 
          * @param vptr {const void*} 数据区指针地址
          * @param dlen {int} 待写的数据区数据长度
          * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示写出错, 应该关闭本地数据流,
          *  ret > 0:  表示成功写了 ret 个字节的数据
          */
    int ACL_VSTREAM::acl_vstream_write( const void *vptr, int dlen){
        if (vptr == NULL || dlen == 0) {
            printf("[errno] %s(%d), %s: vptr %s, dlen %d", __FILE__,
                   __LINE__, __FUNCTION__, vptr ? "not null" : "null", (int) dlen);
            return ACL_VSTREAM_EOF;
        }
        
        if(wbuf_dlen_ > 0){
            acl_vstream_fflush();
        }
        return write_once(vptr, dlen);
    }
    /**
        * 循环向数据流中写 dlen 个字节的数据直至写完或出错为止
        * @param vptr {const char*} 数据区指针地址
        * @param dlen {size_t} 待写的数据区数据长度
        * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示写出错, 应该关闭本地数据流,
        *  ret > 0:  表示成功写了 dlen 个字节的数据
        */
    int ACL_VSTREAM::acl_vstream_writen(const void *vptr, size_t dlen){
        if (vptr == NULL || dlen == 0) {
            printf("[errno] %s(%d), %s: vptr %s, dlen %d", __FILE__,
                   __LINE__, __FUNCTION__, vptr ? "not null" : "null", (int) dlen);
            return ACL_VSTREAM_EOF;
        }

        if (wbuf_dlen_ > 0) {
            acl_vstream_fflush() ;
        }
        return loop_writen(vptr, dlen);
    }

loop_writen、loop_writevn

    int ACL_VSTREAM::loop_writen(const void *vptr, size_t size)
    {
        const unsigned char *ptr = (const unsigned char *) vptr;
        int   once_dlen = 64 * 1024 * 1024;  /* xxx: 以 64KB 为单位写 */
        int   nleft = (int) size, n, len;

        while (nleft > 0) {
            len = nleft > once_dlen ? once_dlen : nleft;
            n = write_once(ptr, len);
            if (n < 0)
                return ACL_VSTREAM_EOF;

            nleft -= n;
            ptr   += n;
        }

        return (int) (ptr - (const unsigned char *) vptr);
    }

    int ACL_VSTREAM::loop_writevn(const struct iovec *vec, int count){
        int   n, i, nskip, nwrite = 0;
        struct iovec *iv, *iv_saved;

        iv = (struct iovec*) calloc(count, sizeof(struct iovec));
        iv_saved = iv;  /* saving the memory for freeing */

        for (i = 0; i < count; i++) {
            iv[i].iov_base = vec[i].iov_base;
            iv[i].iov_len = vec[i].iov_len;
        }

        while (1){
            n = writev_once( iv, count);
            if (n == ACL_VSTREAM_EOF) {
                free(iv_saved);
                return ACL_VSTREAM_EOF;
            } else if (n == 0) {
                continue;
            }

            nwrite += n;
            nskip   = 0;

            for (i = 0; i < count; i++) {
                if (n >= (int) iv[i].iov_len) {
                    /* fully written one vector item */
                    n -= (int) iv[i].iov_len;
                    nskip++;
                } else {
                    /* partially written */
                    iv[i].iov_base = (void *) ((unsigned char*) iv[i].iov_base + n);
                    iv[i].iov_len -= n;
                    break;
                }
            }

            if (i >= count) {
                free(iv_saved);
                return nwrite;
            }

            count -= nskip;
            iv    += nskip;
        }
    }

acl_vstream_write 、acl_vstream_writev

   /**
          * 一次性写入流操作, 返回实际写入的字节数.
          * @param vptr {const void*} 数据区指针地址
          * @param dlen {int} 待写的数据区数据长度
          * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示写出错, 应该关闭本地数据流,
          *  ret > 0:  表示成功写了 ret 个字节的数据
          */
    int ACL_VSTREAM::acl_vstream_write( const void *vptr, int dlen){
        if (vptr == NULL || dlen == 0) {
            logger_error("%s(%d), %s: vptr %s, dlen %d", __FILE__,
                   __LINE__, __FUNCTION__, vptr ? "not null" : "null", (int) dlen);
            return ACL_VSTREAM_EOF;
        }

        if(wbuf_dlen_ > 0){
            if (acl_vstream_fflush() == ACL_VSTREAM_EOF) {
                return ACL_VSTREAM_EOF;
            }
        }
        return write_once(vptr, dlen);
    }
      /**
       * 一次性写入流操作,采用 writev 模式,返回实际写入的字节数
       * @param vector {const struct iovec*}
       * @param count {int} vector 数组的长度
       * @return {int} 返回成功写入的字节数,如果出错,则返回 ACL_VSTREAM_EOF
       */
      int ACL_VSTREAM::acl_vstream_writev(const struct iovec *vec, int count){
          if (vec == NULL || count == 0) {
              logger_error("%s(%d), %s: vptr %s, dlen %d", __FILE__,
                           __LINE__, __FUNCTION__, vec ? "not null" : "null", (int) count);
              return ACL_VSTREAM_EOF;
          }

          if(wbuf_dlen_ > 0){
              if (acl_vstream_fflush() == ACL_VSTREAM_EOF) {
                  return ACL_VSTREAM_EOF;
              }
          }
          return writev_once(vec, count);
      }

acl_vstream_fprintf、acl_vstream_vfprintf、acl_vstream_writen之间的关系

acl_vstream_fprintf、acl_vstream_vfprintf最终都是调用acl_vstream_writen,一直反复写,直到将数据写完。

 /**
        * 循环向数据流中写 dlen 个字节的数据直至写完或出错为止
        * @param vptr {const char*} 数据区指针地址
        * @param dlen {size_t} 待写的数据区数据长度
        * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示写出错, 应该关闭本地数据流,
        *  ret > 0:  表示成功写了 dlen 个字节的数据
        */
   int ACL_VSTREAM::acl_vstream_writen(const void *vptr, size_t dlen){
        if (vptr == NULL || dlen == 0) {
            printf("[errno] %s(%d), %s: vptr %s, dlen %d", __FILE__,
                   __LINE__, __FUNCTION__, vptr ? "not null" : "null", (int) dlen);
            return ACL_VSTREAM_EOF;
        }

        if (wbuf_dlen_ > 0) {
            acl_vstream_fflush();
        }
        return loop_writen(vptr, dlen);
    }

    /**
     * 带格式的流输出, 类似于 vfprintf()
     * @param fmt {const char*} 数据格式
     * @param ap {va_list}
     * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示写出错, 应该关闭本地数据流,
     *  ret > 0:  表示成功写了 dlen 个字节的数据
     */
    int ACL_VSTREAM::acl_vstream_vfprintf( const char *fmt, va_list ap)
    {
        if (fmt == NULL || *fmt == 0) {
            printf("[errno] %s, %s(%d): fmt %s", __FUNCTION__,
                          __FILE__, __LINE__,
                          fmt && *fmt ? "not null" : "null");
            return ACL_VSTREAM_EOF;
        }

#define	ACL_VSTREAM_BUFSIZE	4096
        char buffer[ACL_VSTREAM_BUFSIZE];
        memset(buffer, 0, ACL_VSTREAM_BUFSIZE);
        int   n = vsprintf(buffer, fmt, ap);
        if (n <= 0 ) {
            logger_fatal("%s, %s(%d): len(%d) <= 0",
                          __FUNCTION__, __FILE__, __LINE__, n);
        }else if(n > ACL_VSTREAM_BUFSIZE){
            logger_fatal("%s, %s(%d): len(%d) > 4096",
                   __FUNCTION__, __FILE__, __LINE__, n);
        }

        n = acl_vstream_writen(buffer, n);
        return n;
    }
    /**
     * 带格式的流输出, 类似于 fprintf()
     * @param fmt {const char*} 数据格式 
     * @param ... 变参序列
     * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示写出错, 应该关闭本地数据流,
     *  ret > 0:  表示成功写了 dlen 个字节的数据
     */
    int ACL_VSTREAM::acl_vstream_fprintf(const char *fmt, ...){
        if (fmt == NULL) {
            logger_error("[error] %s, %s(%d): input invalid",
                          __FUNCTION__, __FILE__, __LINE__);
            return ACL_VSTREAM_EOF;
        }

        va_list ap;
        va_start(ap, fmt);
        int n = acl_vstream_vfprintf(fmt, ap);
        va_end(ap);
        return n;
    }

acl_vstream_writen VS acl_vstream_buffed_writen

 /**
        * 循环向数据流中写 dlen 个字节的数据直至写完或出错为止
        * @param vptr {const char*} 数据区指针地址
        * @param dlen {size_t} 待写的数据区数据长度
        * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示写出错, 应该关闭本地数据流,
        *  ret > 0:  表示成功写了 dlen 个字节的数据
        */
    int ACL_VSTREAM::acl_vstream_writen(const void *vptr, size_t dlen){
        if (vptr == NULL || dlen == 0) {
            printf("[errno] %s(%d), %s: vptr %s, dlen %d", __FILE__,
                   __LINE__, __FUNCTION__, vptr ? "not null" : "null", (int) dlen);
            return ACL_VSTREAM_EOF;
        }

        if (wbuf_dlen_ > 0) {
            acl_vstream_fflush();
        }
        return loop_writen(vptr, dlen);
    }
    /**
     * 带缓冲式写
     * @param vptr {const void*} 数据指针起始位置
     * @param dlen {size_t} 要写入的数据量
     * @return {int} 写入的数据量或出错 ACL_VSTREAM_EOF
     */
    int ACL_VSTREAM::acl_vstream_buffed_writen( const void *vptr, size_t dlen){
        if ( vptr == NULL || dlen == 0) {
            logger_error("%s(%d), %s:  vptr %s, dlen %d", __FILE__,
                          __LINE__, __FUNCTION__,
                          vptr ? "not null" : "null", (int) dlen);
            return ACL_VSTREAM_EOF;
        }

        if(wbuf_ == NULL){
            wbuf_size_ = 8192;
            wbuf_ = static_cast<unsigned char *>(malloc(wbuf_size_));
        }

        if (dlen >= (size_t)wbuf_size_) {
            if (acl_vstream_fflush() == ACL_VSTREAM_EOF) {
                return ACL_VSTREAM_EOF;
            } else if(loop_writen(vptr, dlen) == ACL_VSTREAM_EOF){
                return ACL_VSTREAM_EOF;
            }else{
                return (int) dlen;
            }
        }else if (dlen + (size_t) wbuf_dlen_ >= (size_t) wbuf_dlen_) {
            if (acl_vstream_fflush() == ACL_VSTREAM_EOF) {
                return ACL_VSTREAM_EOF;
            }
        }

        memcpy(wbuf_ + (size_t)wbuf_dlen_, vptr, dlen);
        wbuf_dlen_ += (int) dlen;
        return (int) dlen;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值