- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我是那些来这里寻找其他人所问问题答案的人之一,我想我自己新问了些什么,但是经过两天的搜索,没有成功,我决定是时候自己问一些问题了。所以在这里…
我有一个用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);
关于c# - 分段长度前缀导致从缓冲区读取的下一个数据使用不正确的消息长度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12297468/
发布以下查询时,出现错误响应 {"error":{"root_cause":[{"type":"parsing_exception","reason":"[prefix] query does not
我对 Python 和 Django 真的很陌生......我想做的是: 在 Mac OS 10.6.8 上安装 Python 2.7 安装 pip 安装 Django 安装 virtualenvwr
前缀表达式 前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前。 例如: ( 3 + 4 ) × 5 − 6 (3+4)×5-6(3+4)×5−6 对应的前缀表达式就是 - × + 3 4 5 6
如何在Intel C编译器中定义俄语字符串? 在MSVS 2008中,我这样做: _wsetlocale(LC_ALL, L"Russian"); wprintf(L"текст"); 而且有效。 在
这是我到目前为止所得到的: SPECS = $(shell find spec -iname "*_spec.js") spec: @NODE_ENV=test \ @NODE_PAT
我看到了下面的前缀::它代表什么? :abc 是一个关键字,但是 ::abc 是什么? 谢谢,穆尔塔扎 最佳答案 假设当前命名空间是my.app。然后, ::x 是 :my.app/x 的阅读器简写,
我为我的 discord 创建了一个建议功能,用户可以说 +suggest(建议),它会自动发布到另一个 channel 。 有些事情我需要帮助: 将“建议由用户制作”放入标题中,而不是在单独的行中。
#include int main() { int a=1; printf("%d",(++a)++); return 0; } 此代码出现错误 error: invalid lvalue in
我在使用前缀和后缀运算符对数字执行减法时遇到了一个小问题。这是我的程序: public class postfixprefix { public static void main (Strin
当我在 Android native 浏览器中运行 HTML5 兼容性测试时,它会看到 IndexedDB 支持标记为“Prefixed”,而在 Chrome 和其他浏览器中则标记为“Yes”。我知道
我试过重载运算符--前缀,但我有错误,有人帮忙吗? #include #include "Circulo.h" using namespace std; int main() { //par
我正在尝试在我正在制作的这个论坛上创建一个引用功能,当我按下引用时,我只需用 Markdown 填充 textarea ,但唯一的事情是我需要在每行的 markdown 前面加上 > 前缀,这样它就是
friend 之间打赌。sum 变量定义为全局变量。我们有 2 个线程在循环 1..100 上运行并在每个循环中将 sum 递增 1。 打印什么?“和=”? int sum = 0; void fun
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: Post Increment and Pre Increment concept? 谁能明确解释前缀增量与后
从模板类继承时,我需要在派生类中访问的所有基类成员前面加上this: template struct X{ int foo; void bar(); }; template struct
据我所知,在 C++ 中,在同一类的函数成员中调用另一个成员函数不需要“this”前缀,因为它是隐式的。但是,在使用函数指针的特定情况下,编译器需要它。仅当我通过 func 指针为调用包含“this”
例如,考虑以下名称冲突的地方 nest1 : template class nest1 {}; class cls { public: template class nest1 {};
我无法理解下面一段特定代码的逻辑。 int i[] = { 21, 4, -17, 45 }; int* i_ptr = i; std::cout << (*i_ptr)++ << std::endl
有人能给我指出正确的方向吗,我目前有一个可搜索的数据库,但遇到了按标题搜索的问题。 如果标题以“The”开头,那么显然标题将位于“T”部分,避免搜索“The”的好方法是什么?我应该连接两个字段来显示标
我在 2 小时前创建了一个新项目。以与我的旧(不同)项目相同的方式配置它,一切正常。 在我的 podfile 中我有: pod 'CocoaLumberjack', '2.0.0-rc2' 如果我在
我是一名优秀的程序员,十分优秀!