向套接字写数据
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;
}