如何通过服务器套接字将数据安全地流式传输到另一个套接字

本文关键字:套接字 传输 另一个 数据安全 何通过 服务器 | 更新日期: 2023-09-27 17:58:07

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

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

这是通过以前8个字节是两个整数的方式对流进行成帧来实现的,即报头的长度和有效载荷的长度(可以比报头大得多)。

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

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

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

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

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

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

提前感谢!

如何通过服务器套接字将数据安全地流式传输到另一个套接字

我不久前也遇到过类似的情况,我现在还没有完整的解决方案,但我所做的大致如下:

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

希望对有所帮助

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

一部手机需要将您的某些PDU与另一部手机进行通信。它作为客户端连接到另一部手机上的服务器。建立了一对套接字。它将数据发送到服务器套接字。插座对是唯一的——两部手机之间可能发生的任何其他流都不应该中断这一点(当然会减慢速度)。

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

这里有什么我看不见的东西吗?

顺便说一句,Maciek计划通过添加一个"AA"起始字节来支持协议,这是一个很好的想法——依赖于仅发送一个长度作为第一个元素的协议似乎最终总是会出错,并导致节点试图将宇宙中有原子的更多字节排成队列。

Rgds,Martin

好吧,现在我明白了这个问题,(我完全误解了OP网络的拓扑结构——我以为每部手机都在运行TCP服务器和客户端,但PC上只有一台服务器/任何a-la-chatroms)。我不明白为什么不能用互斥锁来锁定套接字类,所以要序列化消息。您可以将消息排队到套接字,但这会带来您试图避免的内存问题。

你可以将一个连接专用于只向手机提供指令,例如"打开另一个套接字连接给我并返回此GUID——然后在套接字上传输消息"。这只会占用一对用于控制的套接字,并使服务器的容量减半:(

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

另一种需要对消息进行分块的替代方案是引入一个"控制消息"(可能是一个开头有55而不是AA的分块),其中包含一个消息ID(GUID?),手机用它来建立与服务器的第二个套接字连接,传递该ID,然后在新的套接字连接上发送第二条消息。

另一种(感到无聊了吗?)说服手机识别出可能正在等待新消息的方法是关闭服务器插座,表明手机正在接收消息。然后,手机可以再次连接,告诉服务器它只得到xxxx字节的消息ID yyyy。然后,服务器可以回复一条指令,为新消息zzzz打开另一个套接字,然后继续发送消息yyyy。这可能需要在服务器上进行一些缓冲,以确保在"中断"期间不会丢失数据。无论如何,你可能想实现这种"中断后重新启动流式传输"功能,因为手机往往会像360MB视频文件的最后一KB流式传输一样穿过桥梁/隧道:(我知道TCP应该处理掉的数据包,但如果手机无线层出于任何原因决定关闭套接字…

这些解决方案都不是特别令人满意。有兴趣了解其他想法。。

Rgds,Martin

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