我想通过TCP套接字使用写系统调用写一个充满BUFF_SIZE
字节的缓冲区:
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
文档说明
write()将从指向的缓冲区写入到文件描述符fd所引用的文件,直到字节数。
当然,写入的实际字节的数量可以通过返回值来检测。然而,如果我想确保我的整个字节缓冲区通过连接发送,那么什么是一个好的方法呢?到目前为止,我在想:
while ( (ch = fgetc(pipe) ) != EOF )
{
buff[ 0 ] = ch;
bytes_in_buff++;
// fill a buffer's worth of data from the pipe
for (int i = 1; i < BUFF_SIZE; ++i, ++bytes_in_buff)
{
if ( (ch = fgetc(pipe) ) == EOF)
break;
buff[ i ] = ch;
}
// write that buffer to the pipe
int bytes_sent = 0;
while (bytes_sent < BUFF_SIZE)
{
bytes_sent = write(fd, buff, bytes_in_buff);
}
}
但是,当然,如果我继续每次发送整个缓冲区,一些多余的字节将被发送bytes_sent < BUFF_SIZE
。
看一下下面的函数,它在write()
周围循环,直到从b
写入s
字节或发生致命错误:
int writen(const int sd, const char * b, const size_t s, const int retry_on_interrupt)
{
size_t n = s;
while (0 < n)
{
ssize_t result = write(sd, b, n);
if (-1 == result)
{
if ((retry_on_interrupt && (errno == EINTR)) || (errno == EWOULDBLOCK) || (errno == EAGAIN))
{
continue;
}
else
{
break;
}
}
n -= result;
b += result;
}
return (0 < n) ?-1 :0;
}
这样写:
int retry_on_interrupt = ... /* {0|1} depending on wether a signal reception shall abort the write operation or not. */
int result = writen(fd, buff, sizeof(buf), retry_on_interrupt)
if (-1 == result)
{
perror("writen()");
}
如果write()
的返回值小于BUFF_SIZE
,建议的循环将永远不会终止;你需要检查是否有错误。
你需要这样写:
while (bytes_in_buff > 0)
{
bytes_sent = write(fd, buff, bytes_in_buff);
if (bytes_sent < 0)
{
perror("write"); // or whatever
break;
}
buff += bytes_sent;
bytes_in_buff -= bytes_sent;
}
然而这个问题已经在news:comp.protocols上广泛讨论过。TCP - IP在几年前,这是TCP/IP实实者的地方,在那里达成了协议,在阻塞模式下,write()
和send()
必须在返回之前发送整个缓冲区。
您需要编辑您为写入提供的参数,以说明您已经发送的数据。像这样:
int bytes_sent = 0;
int remaining = BUFF_SIZE;
while (remaining)
{
bytes_sent = write(fd, buff, remaining);
remaining -= bytes_sent;
buff += bytes_sent;
}