有啥方法可以检查在 C 中的缓冲区中写入了多少数据/字节

Posted

技术标签:

【中文标题】有啥方法可以检查在 C 中的缓冲区中写入了多少数据/字节【英文标题】:Is there any way to check how much data/bytes is written in buffer in C有什么方法可以检查在 C 中的缓冲区中写入了多少数据/字节 【发布时间】:2020-12-09 13:25:13 【问题描述】:

有什么方法可以检查缓冲区中写入的确切字节数?我想使用socket.send() 动态设置我通过套接字发送的数据量。现在我有问题,假设我的文件是 200KB,我的缓冲区设置为 24KB,所以我需要发送 9 个包,我的输出文件是 216KB 大而不是 200KB 作为输入。有没有办法处理这些空字节?

【问题讨论】:

我认为这只是一个简单的数学计算和循环。 标准 C++ 中没有套接字类,因此您必须包含有关您使用的库的信息。您是否检查过您发送的文件和收到的文件的 bytes 大小? 这只是基础数学,不是吗?记下你写了多少字节,你已经知道你总共要写多少字节,一次可以写多少字节......所以这只是对std::max的调用......不? 或者std::min 实际上:D send 不发送包裹。除非您使用的是 UDP,否则您可能不是。请注意 TCP 没有软件包。您可能发送 24KB,然后 recv 将决定只接收 16KB,然后在您下次调用时接收另外 8KB! 【参考方案1】:

socket.send 我不认识。我假设您的意思是在某些 socket(7) 上使用 send(2)。

在许多情况下(想想一些 tcp(7) 流量通过几个 Wifi 路由器),数据包可能是 fragmented。因此,一侧的给定send(2) 可能对应于接收侧的几个 recv(2),反之亦然。

然后您需要以某种方式管理您的数据包数据(例如,计算和缓冲发出的数据和接收的数据)。在实践中,您需要一些关于它们的文档化约定。 HTTP 或 SMTP 或 JSONRPC 或 ONCRPC 或 MQTT 可能是鼓舞人心的。

您会找到可能有用的库。例如。 libcurl、Wt、Qt、POCO、libonion。它们是开源的,因此您可以研究它们的源代码。

您还可以研究知名开源服务器的源代码,例如lighttpd、postfix 等...或从其他用 C++ 编写的开源项目中获得灵感,包括Clang static analyzer、@ 987654340@ 或fish 或github 或gitlab 上的许多其他人。

您在CC++ 都标记了您的问题,但它们是非常不同的语言。请参阅this reference 了解更多信息。

顺便说一句,Clang static analyzer 应该会有所帮助。如果您使用最近的 GCC 编译您的 C++ 代码,请确保启用所有警告和调试信息,因此使用 g++ -Wall -Wextra -g 进行编译(稍后使用 GDB 调试器)

有什么方法可以检查在 C 中的缓冲区中写入了多少数据/字节

是的,因为 send(2) 和 write(2)(以及 recv(2) 和 read(2))都会在成功时返回字节数。

您的event loop 将处理它们(计数字节、管理缓冲区)并使用poll(2) 或其他一些多路复用系统调用。在这种情况下,您可以找到有用的库(libev、libevent 等...)

请注意,我们在 2020 年拥有UTF-8 everywhere。因此,即使对于文本输入,一些字母(如俄语 Ы 或法语 à 或您所居住的城市波兹南的最后一个字母......)可能需要超过一个字节。当您发送文本信息时,这会增加代码的复杂性。

【讨论】:

现在我想发送一些元数据并动态更改缓冲区的内存。非常感谢,我会看看你发来的这些库。 这个答案主要是一堆链接,与手头的实际问题没有真正的关系。 @AsteroidsWithWings:那为什么会被接受? @BasileStarynkevitch 打败了我。 @AsteroidsWithWings:“打败我”是什么意思?顺便说一句,我是法国人。谁在伤害你?为什么?【参考方案2】:

最好的办法是自己计算这些字节数,因为您始终知道自己正在写入多少字节。

如果你有 200KB 要发送,并且一次可以发送 24KB,那么它只是(在伪代码中):

const int chunkSize = 24*1024;
const int inputSize = 200*1024;

char input[inputSize];   // N.B. VLAs not actually valid C++; this is pseudo-code
int bytesSent = 0;

while (true)

   const int bytesRemaining = inputSize - bytesSent;
   const int bytesToSend = std::min(chunkSize, bytesRemaining);
   
   if (bytesToSend == 0)
   
      // Done!
      break;
   
   
   const int bytesWritten = send(&input[bytesSent], bytesToSend);
   
   if (bytesWritten == 0)  // I'm assuming 0 written means error; adjust for your API
   
      // Error! Handle it.
      break;
   
   
   bytesSent += bytesWritten;
   
   if (bytesSent > inputSize)
   
      // Something went horribly wrong
      break;
   

简单?。

(实际上,您可能应该使用一些无符号类型,例如 std::size_t,而不是 int,除非您的 send 在错误时返回一些负值。)

bytesToSend 是这里的关键。您可能不想在最后一次迭代中发送“完整”块。这就是你额外的 16KB 的来源:你的输入不是块大小的精确倍数。

【讨论】:

投反对票的人想留下一些建议吗? A TCP send() 永远不会返回 0,它会在失败时返回 0。我还将while (true) 更改为while (bytesSent < inputSize) 并摆脱if (bytesToSend == 0)。此外,根据所显示的数学,if (bytesSent > inputSize) 永远不会是真的,所以也摆脱它:while (bytesSent < inputSize) const int bytesToSend = std::min(chunkSize, inputSize - bytesSent); const int bytesWritten = send(&input[bytesSent], bytesToSend); if (bytesWritten < 0) /* error */ break; bytesSent += bytesWritten; @RemyLebeau 正如我所说,这取决于您使用的 API。你说的是POSIX,我想这很好。正如我所指出的,相应地调整逻辑。我更喜欢按原样列出的条件。 if (bytesSent > inputSize) 永远不会是真的” 如果出现严重错误并且bytesWritten 不是应有的样子,这就是评论所说的以及我们放弃的原因(@987654334 @) 在这种情况下(即不要做假设!) @RemyLebeau 如果你愿意,你可以用你自己的代码风格编写你自己的答案:) "如果出现可怕的错误,它会发生" - 你想象的究竟会发生什么?鉴于显示的代码,除非调用线程的堆栈内存被另一个线程、错误的驱动程序或硬件故障损坏,否则没有其他任何东西可以导致 bytesSent > inputSize 条件发生。

以上是关于有啥方法可以检查在 C 中的缓冲区中写入了多少数据/字节的主要内容,如果未能解决你的问题,请参考以下文章

在C和/或C ++中创建和管理内存中的字节缓冲区,可以根据需要自动调整大小

C 语言文件操作 ( fflush 函数 | 刷新缓冲区示例代码 )

Java NIO使用及原理分析 来自网上资料整理

c语言中的getch与getchar 有啥区别?

怎么清楚sql sever中的记录

循环遍历存储在 C 中缓冲区中的数据