static int socket_write(int fd, char *buffer, int len)
{
int ret_len = 0;
int sub;
do {
sub = write(fd, buffer + ret_len, len - ret_len);
if (sub > 0) {
ret_len += sub;
}
else {
if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
continue;
else
return -1;
}
} while (ret_len < len);
return ret_len;
}
这种socket_write
函数的设计是为了确保能够尽可能地将给定的数据(buffer
)完全写入到套接字(socket)中,即使在这个过程中可能会遇到中断或其他导致write
调用返回少于请求字节数的情况。以下是使用这种方式发送数据的一些原因:
-
处理非阻塞套接字(Non-blocking sockets):
当套接字设置为非阻塞模式时,如果数据不能立即发送(例如,由于网络拥塞或接收端缓冲区已满),write
调用可能会返回EWOULDBLOCK
或EAGAIN
错误。通过在循环中重试write
调用,此函数允许非阻塞套接字在准备好发送更多数据时继续发送数据。 -
处理被中断的系统调用(Interrupted system calls):
如果一个write
调用被信号中断(例如,由于程序接收到了信号),它会返回-1
并设置errno
为EINTR
。通过检查这个错误并重新尝试write
调用,这个函数可以处理这种中断情况。 -
确保数据的完整发送:
由于网络或操作系统的各种因素,write
调用可能无法一次发送所有请求的数据。通过在循环中调用write
,并更新发送的字节数(ret_len
),这个函数确保所有数据都被发送,直到达到请求的长度(len
)或遇到不可恢复的错误为止。 -
错误处理:
除了EINTR
、EWOULDBLOCK
和EAGAIN
之外,如果write
调用返回-1
并设置了其他errno
值,这通常表示发生了不可恢复的错误(如EBADF
、ENOMEM
等)。在这种情况下,函数返回-1
,表明发生了错误。 -
灵活性:
此函数适用于阻塞和非阻塞套接字,增加了代码的灵活性和可重用性。 -
性能考虑:
虽然这种方法的性能可能不如单个write
调用(如果数据可以一次发送),但在某些情况下(如网络拥塞或套接字为非阻塞模式),它可以提供更好的整体性能和响应性。
总之,这种设计允许函数更健壮地处理各种可能的网络条件和错误情况,并确保数据的完整发送。