0

我在 Windows Phone 7 应用程序中使用伪同步套接字。我的套接字代码基于http://msdn.microsoft.com/en-us/library/hh202858(v=vs.92).aspx中的示例。

服务器的发送模式有些不可预测。它以包含消息其余部分的长度的固定大小的标头开始。我首先读入了这个头文件,然后我从套接字中读取了指定数量的字节。

由于我还需要向服务器发送消息,并且我尝试将套接字与一个用于接收的线程和另一个用于发送的线程进行双工导致了很多问题,所以我的代码中有一个这样的循环:

while (KeepConnectionGoing)
        {
            byte[] Rcvd;
            Rcvd = Socket.Receive();//Returns null if no message received in 50 ms
            if (Rcvd != null)
            {
                ParseMessage(Rcvd);
            }

            if (HasMessageThatNeedsToBeSent())
            {
                byte[] Message = GetMessageToSend();
                Socket.Send(Message);
            }
        }

这在大多数情况下都可以正常工作,但是当消息为空时会发生奇怪的事情。因为 Receive 方法中的超时(请参阅链接示例)使用 ManualResetEvent,所以套接字上的接收请求永远不会真正取消。即使该方法返回,该请求也会在某个地方等待,并且当套接字上的数据可用时,会占用头部。事件处理程序与它接收到的数据无关(因为方法已经返回并且方法中的变量永远不会再被使用),数据基本上消失了。我希望返回标头跳过的读取请求读取标头之后的字节,我不知道消息有多长。

如果套接字超时,我希望能够取消所有未完成的请求。我正在使用示例中的匿名方法,因为它简化了所有事情,并让我不必自己编写所有状态传输代码。因此,我无法解开事件处理程序。我认为,即使我使用一个方法作为事件处理程序,但在异步操作完成之前取消挂钩,仍然会调用回调方法。(我没有测试过,这只是我的理解)

现在,我能看到的唯一解决方案是将一些静态字节数组组合在一起(即具有静态字节 [] 标头,如果它为空,我会读取标头,否则我会阅读消息),但这似乎真的不优雅的解决方案并且很容易出现竞争条件。

有没有更好的办法?

谢谢

4

1 回答 1

0

看来确实没有什么好的方法可以做到这一点。轮询方法会很好,但 Silverlight 没有它。我拼凑了一个解决方案,使用静态标志告诉我我处于什么状态(是否请求了标头,是否请求了消息),长度的静态 int 和静态缓冲区。

在方法的开头,可以请求标头或主体。如果已请求标头,则线程将等待,直到有效的正文长度可用。如果此等待超时,则意味着标头接收操作仍处于挂起状态,但确实没有可用的消息。否则,它会读取该长度的消息。

如果尚未请求标头,则接收标头。在事件处理程序中,完成后,检查控制流是否已经继续(即接收操作花费了太长时间,因此函数已经返回,但现在实际上已经完成)。更新长度,然后请求正文,除非它超时。

于 2012-08-14T23:48:24.270 回答