ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

片段长度前缀导致下一次从缓冲区读取的数据使用错误的消息长度

2019-11-27 18:08:37  阅读:230  来源: 互联网

标签:asynchronous tcp protocol-buffers c


我是来这里寻找其他人提出的问题的答案的人之一,我想我是自己较新的人,但是经过两天的搜索失败后,我决定该是时候问自己一个问题了.所以这是…

我有一个使用SocketAsyncEventArgs用C#、. NET 4,异步套接字编写的TCP服务器和客户端.我有一个长度为前缀的消息框架协议.总体而言,一切正常,但一个问题一直困扰着我.

情况是这样的(我将以小数为例):

可以说服务器的发送缓冲区长度为16个字节.
它发送一条消息,该消息长6个字节,并以4个字节长的前缀作为前缀.消息总长度为6 4 = 10.

客户端读取数据并接收一个16字节长的缓冲区(是10字节数据和6字节等于零).

收到的缓冲区如下所示:6 0 0 0 56 21 33 1 5 7 0 0 0 0 0 0

所以我读取了前4个字节,这是我的长度前缀,我确定我的消息是6个字节长,我也阅读了它,到目前为止一切都很好.然后我还有16-10 = 6个字节要读取.它们都是零,我读了其中的4个,因为这是我的长度前缀.因此,它是零长度的消息,被允许作为保持活动数据包.

剩余要读取的数据:0 0

现在的问题“开始”.我只剩下2个字节要读取,它们不足以完成一个4字节长的前缀缓冲区.因此,我读取了这2个字节,并等待更多的传入数据.现在服务器不知道我仍在读取长度前缀(我只是在读取缓冲区中的所有那些零)并发送另一条正确地以4字节为前缀的消息.客户端假定服务器发送了丢失的2个字节.我在客户端接收数据,并读取前两个字节以形成完整的4字节长的缓冲区.结果是这样的

lengthBuffer =新字节[4] {0,0,42,0}

然后将其转换为2752512消息长度.因此,我的代码将继续读取下一个2752512字节以完成消息…

因此,在每个单个消息框架示例中,我都看到零长度消息被支持为保持活动状态.而且我所看到的每个示例都没有比我做的更多的事情.问题是当我从服务器收到数据时,我不知道必须读取多少数据.由于我的缓冲区部分填充了零,因此我必须全部读取,因为这些零可能是我从连接另一端发送的保持活动状态.

我可以丢弃零长度的消息,并在第一个空消息之后停止读取缓冲区,它应该可以解决此问题,并为我的保持活动机制使用自定义消息.但是我想知道我是否丢失了某些东西,或者做错了什么,因为我所看到的每个代码示例似乎都存在相同的问题(?)

更新

马克·格雷夫(Marc Gravell),您的先生从我嘴里说出了话.即将更新问题在于发送数据.问题是,最初在探索.NET套接字和SocketAsyncEventArgs时,我遇到了以下示例:http://archive.msdn.microsoft.com/nclsamples/Wiki/View.aspx?title=socket%20performance
它使用可重用的缓冲池.简单地获取允许的最大客户端连接数的预定义数量(例如10),获取单个缓冲区的最大大小(例如512),并为所有缓冲区创建一个大缓冲区.因此512 * 10 * 2(用于发送和接收)= 10240
所以我们有byte [] buff = new byte [10240];
然后,为每个连接的客户端分配一个大缓冲区.首先连接的客户端为数据读取操作获取前512个字节,为数据发送操作获取下一个512字节(偏移512).因此,代码最终已经分配了大小为512(恰好是客户端以后作为BytesTransferred接收到的数字)的发送缓冲区.该缓冲区中填充了数据,这512个字节中的所有剩余空间都以零发送.

这个例子很奇怪,来自msdn.之所以只有一个巨大的缓冲区,是为了避免出现碎片化的堆内存,当缓冲区被固定并且GC无法收集它时,诸如此类.

在提供的示例中来自BufferManager.cs的注释(请参见上面的链接):

This class creates a single large buffer which can be divided up and
assigned to SocketAsyncEventArgs objects for use with each socket I/O
operation. This enables bufffers to be easily reused and gaurds
against fragmenting heap memory.

因此,问题很明显.欢迎提出任何有关如何解决此问题的建议:)他们所说的零散堆内存是否正确,可以“快速”创建数据缓冲区吗?如果是这样,当服务器扩展到几百甚至数千个客户端时,我会遇到内存问题吗?

解决方法:

这听起来像是您发送或接收代码中的错误.您应该只将BytesTransferred作为实际发送的数据,或者比分批到达时小的数字.我想知道的第一件事是:您是否正确设置了发送?即,如果您的缓冲区过大,则正确的实现可能如下所示:

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

这里的realBytesToSend可以比buffer.Length小得多.我最初的怀疑是
您正在执行以下操作:

args.SetBuffer(buffer, 0, buffer.Length);

因此发送的数据量超出了您实际填充的数据量.

我应该强调:您的发送或接收中有问题;我不相信,至少在没有示例的情况下,这里的BCL中存在一些基本的潜在错误-我广泛使用了异步API,并且工作正常-但您确实需要准确跟踪在以下位置发送和接收的数据所有要点.

标签:asynchronous,tcp,protocol-buffers,c
来源: https://codeday.me/bug/20191127/2076092.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有