有啥方法可以检查在 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 上的许多其他人。
您在C
和C++
都标记了您的问题,但它们是非常不同的语言。请参阅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 TCPsend()
永远不会返回 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 ++中创建和管理内存中的字节缓冲区,可以根据需要自动调整大小