使用write()系统调用编写完整缓冲区

时间:2014-06-17 08:59:28

标签: c sockets buffer

我想使用write system call在TCP套接字上编写一个填充BUFF_SIZE字节的缓冲区:

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

documentation表示

  

write()将从缓冲区指向的buf中的字节写入文件描述符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继续发送整个缓冲区,就会发送一些冗余字节。

3 个答案:

答案 0 :(得分:2)

如果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上讨论了 in extenso ,这是TCP / IP实现者挂出的地方,并且在那里同意,在阻塞模式下,write()send()必须在返回之前发送整个缓冲区。

答案 1 :(得分:2)

查看以下函数,该函数循环write(),直到s的{​​{1}}字节被写入或发生致命错误:

b

这样称呼:

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;
}

答案 2 :(得分:1)

您需要编辑您为写入的参数编写您已发送的数据。所以像这样:

int bytes_sent = 0;
int remaining = BUFF_SIZE;
while (remaining) 
{
  bytes_sent = write(fd, buff, remaining);
  remaining -= bytes_sent;
  buff += bytes_sent;
}