0

我正在为正在设计的 iPhone 应用程序编写服务器应用程序。iPhone 应用程序是用 C# (MonoTouch) 编写的,服务器也是用 C# 编写的 (.NET 4.0)

我在网络层使用异步套接字。服务器允许两个或多个 iPhone(“设备”)相互连接并能够双向发送数据。根据传入的消息,服务器要么自己处理消息,要么将数据中继到与发送设备相同的组中的其他设备。它可以通过首先解码数据包的标头并确定它是什么类型的数据包来做出这个决定。

这是通过以前 8 个字节为两个整数的方式来构建流的,即标头的长度和有效负载的长度(可以比标头大得多)。

服务器从套接字(异步)读取前 8 个字节,因此它具有两个部分的长度。然后它再次读取,直到标题部分的总长度。

然后它对标头进行反序列化,并根据其中的信息,可以查看是否应将剩余数据(有效负载)转发到另一台设备,或者是否应该由服务器本身处理。如果需要将其转发到另一台设备,那么下一步是以 1024 字节为单位读取进入套接字的数据,并通过连接到接收设备的另一个套接字使用异步发送直接写入这些数据。

这减少了服务器的内存需求,因为我没有将整个数据包加载到缓冲区中,然后将其重新发送到接收方。

但是,由于异步套接字的性质,我不能保证在一次读取中接收到整个有效负载,因此必须继续读取直到我收到所有字节。在中继到其最终目的地的情况下,这意味着我正在为从发送者接收到的每个字节块调用 BeginSend(),并将该块转发给接收者,一次一个块。

这样做的问题是,因为我使用的是异步套接字,这使得另一个线程有可能对同一个接收者(因此也是相同的最终目标套接字)进行类似的操作,因此来自两个线程的块很可能会混淆并破坏发送给该收件人的所有数据。例如:如果第一个线程发送一个块,并且正在等待来自发送者的下一个块(因此它可以转发它),那么第二个线程可以发送它的一个数据块,并破坏第一个线程的(以及第二个线程就此而言)数据。

当我写这篇文章时,我只是想知道它是否像锁定套接字对象一样简单?!这会是正确的选择,还是会导致其他问题(例如:通过锁定的套接字接收从远程设备发回的数据时出现问题?)

提前致谢!

4

3 回答 3

2

不久前我遇到了类似的情况,我不再有完整的解决方案,但这几乎是我所做的:

  • 我没有使用同步套接字,决定探索 C# 中的异步套接字 - 有趣的旅程
  • 我不允许多个线程共享一个资源,除非我真的必须这样做
  • 我的“数据包”包含有关消息的大小、索引和总数据包计数的信息
  • 我的数据包的第一个字节是唯一的,表示它是消息的开始,我使用 0xAA
  • 我的数据包的最后 2 个字节是 CRC-CCITT 校验和 (ushort) 的结果
  • 执行接收位的对象包含一个包含所有接收字节的缓冲区。一旦大小合适,我就从该缓冲区中提取“完整”消息,并且校验和匹配
  • 我需要做的唯一“锁定”是在临时缓冲区中,这样我就可以在写/读操作之间安全地分析它的内容

希望那有所帮助

于 2011-05-31T14:01:11.937 回答
0

不确定问题出在哪里。既然你提到了服务器,我假设是 TCP,是吗?

一部电话需要将您的一些 PDU 传送到另一部电话。它作为客户端连接到另一部电话上的服务器。建立了一个套接字对。它将数据发送到服务器套接字。套接字对是独一无二的——两部手机之间可能发生的其他流不会中断这一点,(当然会减慢它的速度)。

我看不出异步/同步套接字(假设实现正确)应该如何影响这一点,或者应该可以正常工作。

有什么我在这里看不到的吗?

顺便说一句,Maciek 计划通过添加“AA”起始字节来支持协议是一个绝妙的主意 - 协议依赖于仅发送一个长度,因为第一个元素似乎最终总是会搞砸并导致节点试图将更多字节出列宇宙中有原子。

Rgds,马丁

好的,现在我明白了问题所在,(我完全误解了 OP 网络的拓扑结构——我以为每部手机都在运行 TCP 服务器和客户端,但 PC 上只有一个服务器/无论什么聊天室)。我不明白为什么你不能用互斥锁锁定套接字类,所以序列化消息。您可以将消息排队到套接字,但这具有您试图避免的内存影响。

您可以专门建立一个连接来仅向电话提供指令,例如“打开另一个套接字连接给我并返回此 GUID - 然后将在套接字上传输一条消息”。这使用了一个套接字对,仅用于控制并将服务器的容量减半:(

您是否坚持您所描述的协议,或者您可以将您的消息分成多个块,每个块中有一些 ID?然后,您可以将消息多路复用到一对套接字上。

另一种选择,同样需要对消息进行分块,是引入一个“控制消息”(可能是一个开头为 55 而不是 AA 的块),其中包含一个消息 ID(GUID?),电话用来建立一个与服务器的第二个套接字连接,传递 ID,然后在新的套接字连接上发送第二条消息。

另一种(感到无聊吗?)说服电话认识到可能正在等待新消息的方法是关闭电话正在接收消息的服务器套接字。然后电话可以再次连接,告诉服务器它只收到了 xxxx 字节的消息 ID yyyy。然后,服务器可以回复一条指令,为新消息 zzzz 打开另一个套接字,然后继续发送消息 yyyy。这可能需要在服务器上进行一些缓冲,以确保在“中断”期间没有数据丢失。无论如何,您可能希望实现这种“中断后重新启动流式传输”功能,因为手机往往会在 360MB 视频文件的最后 KB 流式传输时通过桥接/隧道 :( 我知道 TCP 应该处理丢弃的数据包,

这些解决方案都不是特别令人满意。有兴趣看看为什么会出现其他想法。

Rgds,马丁

于 2011-05-31T14:37:26.930 回答
0

感谢大家的帮助,我意识到最简单的方法是在客户端上使用同步发送命令,或者至少是在发送下一个项目之前必须完成的发送命令。我在客户端使用自己的发送队列来处理这个问题,而不是应用程序的各个部分在需要发送内容时调用 send()。

于 2011-06-07T06:55:18.203 回答