【问题标题】:max size_t value on send() in CC 中 send() 的最大 size_t 值
【发布时间】:2019-09-25 10:01:33
【问题描述】:

我正在用 C 语言编写一个 tcp 服务器,但在发送时遇到了问题。我读取本地文件并将数据发送回客户端,当文件很小时我没有问题,但是当文件变大时我有这种奇怪的情况:

服务器 tcp:

 // create socket, bind, listen accept

// read file
fseek(fptr, 0, SEEK_SET);
// malloc for the sending buffer
ssize_t read = fread(sbuf, 1, file_size, fptr);

while(to_send>0) {
  sent = send(socket, sbuf, buf_size, 0);
  sbuf += sent;
  to_send -= sent;
}

在发送的大文件等于 size_t 的最大值时,我认为我有缓冲区溢出。我怎样才能防止这种情况?从文件中读取并将其发回的最佳做法是什么?

【问题讨论】:

  • sent 是什么类型? send 返回一个 ssize_t 类型的值
  • 我已发送 ssize_t
  • 你好像没有检查send的返回值不小于0,你怎么知道成功了?
  • 我正在逐步构建这个方法,现在我有一个 printf 可以检查,并且在小文件上一切正常
  • 通常最好以块的形式读取文件(例如 8192 字节)并将每个块的写入发送回套接字。这样您就不必分配大量内存来处理此请求。此外,无论如何,您的数据都会在 tcp/ip 级别被分割成块。因此,尝试在一次调用中发送所有信息并没有任何优势。

标签: c sockets send


【解决方案1】:

问题是您每次都发送buf_size 字节,即使剩下的不多。

例如,假设 buf_size 是 8,而您发送 10 个字节(所以最初,to_send 也是 10)。第一个send发送了8个字节,所以你需要再发送2个。第二次,您还发送了 8 个字节(这可能会超出范围)。然后,to_send 将是 -6,与 SIZE_MAX - 5 相同。

简单的解决方法是发送to_send(如果它更小):

sent = send(socket, sbuf, to_send < buf_size ? to_send : buf_size, 0);

此外,send 如果不成功,则返回 -1。这与分配给size_t 时的SIZE_MAX 相同。你需要一些错误处理来解决这个问题。

【讨论】:

  • 不需要分支。 OP 应该首先 to_send 到缓冲区的大小,然后将其减少发送字节数的值,并将其用作 send 函数的大小参数。
【解决方案2】:

我认为在发送的大文件上等于 size_t 的最大值 我有一个缓冲区溢出。

由于sent 将其值作为send() 的返回值,而send() 返回ssize_t,这是一个不太可能比size_t 宽的有符号类型,因此几乎可以肯定实际上是发生的是send() 通过返回-1 来指示错误。在这种情况下,它还会将errno 设置为指示错误的值。在我使用过的任何系统上,它都无法返回 size_t 的最大值。

如何防止这种情况发生?

首先,在您担心预防它之前,您应该确保通过

检测
  1. sent 声明为ssize_t 以匹配send() 的返回类型,而不是size_t,并且
  2. 检查返回到sent 的值是否存在此类错误情况。

其次,如果您确实处理的文件比ssize_t(更不用说size_t)所能表示的文件更长,那么在发送任何文件之前将整个文件加载到内存中是一个糟糕的主意。相反,将其加载到(很多)更小的块中,并一次发送一个这样的块。这不仅会降低感知延迟,而且还可以避免与接近所涉及的数据类型限制相关的任何风险。

此外,当您这样做时,请注意正确操作。您已经很好地将send() 调用包装在一个循环中以解决短写问题,但是正如@Artyer 在他的回答中所描述的那样,您并不完全正确,因为您没有减少尝试发送的字节数在第二次和随后的电话中。

什么是 从文件中读取并将其发回的最佳做法?

如上。

【讨论】:

  • 我的文件大小适合 ssize,我有一个 errno=32 -> SIGPIPE
猜你喜欢
  • 1970-01-01
  • 2014-04-26
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 2011-03-27
  • 2013-02-02
  • 1970-01-01
相关资源
最近更新 更多