gpt4 book ai didi

c# - 分段长度前缀导致从缓冲区读取的下一个数据使用不正确的消息长度

转载 作者:可可西里 更新时间:2023-11-01 02:34:04 24 4
gpt4 key购买 nike

我是那些来这里寻找其他人所问问题答案的人之一,我想我自己新问了些什么,但是经过两天的搜索,没有成功,我决定是时候自己问一些问题了。所以在这里…
我有一个用C,.NET 4编写的TCP服务器和客户端,使用SocketAsyncEventArgs异步套接字。我有一个以长度为前缀的消息帧协议。总的来说一切都很好,但有一个问题一直困扰着我。
情况是这样的(我将使用小数字作为示例):
假设服务器的发送缓冲区长度为16字节。
它发送一条6字节长的消息,并以4字节长的前缀作为前缀。总消息长度为6+4=10。
客户机读取数据并接收16个字节长度的缓冲区(是的,10个字节的数据,6个字节等于零)。
接收的缓冲区如下:6 0 0 0 56 21 33 1 5 7 0 0 0 0 0
所以我读了前面的4个字节,这是我的长度前缀,我确定我的消息是6个字节长,我也读了它,到目前为止一切都很好。然后我还有16-10=6个字节要读。它们都是0,我读了4个,因为这是我的长度前缀。所以这是一个零长度的消息,它被允许作为keep-alive包。
要读取的剩余数据:0 0
现在问题“开始”。我只剩下2个字节要读,它们不足以完成一个4字节长的前缀缓冲区。所以我读取这两个字节,然后等待更多的输入数据。现在服务器不知道我还在读取长度前缀(我只是在读取缓冲区中的所有零)并发送另一条前缀为4字节的消息。客户机假设服务器发送了丢失的2个字节。我在客户端接收数据,并读取前两个字节以形成一个完整的4字节长的缓冲区。结果是这样的
lengthBuffer=新字节[4]{0,0,42,0}
然后转换成2752512信息长度。所以我的代码将继续读取接下来的2752512字节来完成消息…
所以在每一个消息帧示例中,我都看到零长度的消息被支持为keep-alive,而我看到的每一个示例所做的都比我所做的要少。问题是,当我从服务器接收数据时,我不知道需要读取多少数据。因为我已经用零部分填充了缓冲区,所以我必须读取它,因为这些零可能是我从连接的另一端发送的keep alive。
我可以删除零长度的消息,并在第一条空消息之后停止读取缓冲区,它应该可以解决此问题,并为我的keep alive机制使用自定义消息。但是我想知道我是否遗漏了一些东西,或者做了一些错误的事情,因为我看到的每个代码示例似乎都有相同的问题(?)
更新
马克·格雷弗尔,先生,你把话从我嘴里说了出来。即将更新发送数据时出现的问题。问题是,最初在探索.NET套接字和SocketAsyncEventArgs时,我遇到了这个示例:http://archive.msdn.microsoft.com/nclsamples/Wiki/View.aspx?title=socket%20performance
它使用可重用的缓冲池。只需预先定义允许的最大客户机连接数(例如10),就可以获得最大单个缓冲区大小(例如512),并为所有连接创建一个大缓冲区。所以512*10*2(发送和接收)=10240
所以我们有byte[]buff=newbyte[10240];
然后为每个连接的客户机分配一个这个大缓冲区。第一个连接的客户机为数据读取操作获取前512个字节,为数据发送操作获取后512个字节(偏移量512)。因此,代码最终已经分配了大小为512的发送缓冲区(确切地说,是客户机以后作为bytesTransferred接收的数字)。这个缓冲区填充了数据,512字节中的所有剩余空间都以零的形式发送。
很奇怪,这个例子来自msdn。之所以有一个巨大的缓冲区是为了避免零碎的堆内存,当缓冲区被固定并且GC不能收集它或者类似的东西时。
BufferManager.cs在提供的示例中的注释(请参见上面的链接):
这个类创建一个大的缓冲区,它可以被划分为
分配给SocketAsyncEventArgs对象以用于每个套接字I/O
操作。这使得buffer可以很容易地被重复使用和使用。
防止堆内存碎片化。
所以问题很明显。关于我应该如何解决这个问题的任何建议都是受欢迎的:)他们所说的碎片堆内存是真的吗,是否可以“动态”创建一个数据缓冲区?如果是这样,当服务器扩展到几百甚至数千个客户机时,我会有内存问题吗?

最佳答案

这听起来就像是发送或接收代码中的错误。您应该只得到实际发送的数据,或者如果是以片段的形式到达,那么应该得到比这小一些的数字。我想知道的第一件事是:你设置的发送是否正确?例如,如果缓冲区过大,则正确的实现可能如下所示:

args.SetBuffer(buffer, 0, actualBytesToSend);
if (!socket.SendAsync(args)) { /* whatever */ }

其中, BytesTransferred可以远小于 actualBytesToSend。我最初的怀疑是
你在做这样的事情:
args.SetBuffer(buffer, 0, buffer.Length);

因此发送的数据比实际填充的要多。
我要强调的是:无论是发送还是接收,都有一些问题;我不相信,至少没有一个例子,BCL中存在一些基本的底层错误-我广泛使用异步API,而且它工作正常-但您确实需要准确地跟踪您发送的数据i所有点的NG和接收。

关于c# - 分段长度前缀导致从缓冲区读取的下一个数据使用不正确的消息长度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12297468/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com