2011-01-11 85 views
33

当然,如果没有数据,BeginReceive()将永远不会结束。 MSDN suggests,致电Close()将中止BeginReceive()如何中止socket的BeginReceive()?

然而,呼吁在插座上Close()还执行就可以了Dispose(),如this great ansewr想通了,结果因为对象已经布置EndReceive()将抛出一个异常(和它呢!)。

我该如何继续?

+0

http://stackoverflow.com/questions/1921611/c-how-do-i-terminate-a-socket-before-socket-beginreceive-calls-back – SwDevMan81 2011-01-11 21:05:10

回答

40

这似乎是(非常愚蠢的)设计。您必须抛出此异常并将其捕获到您的代码中。

MSDN看起来沉默是确实的,但如果你看看另一个异步socket方法,BeginConnect()的文档,这里是我们发现:

取消挂起的调用 BeginConnect()方法,关闭 套接字。当正在进行异步操作 时调用Close()方法 时,向BeginConnect()方法提供 的回调调用 。随后调用 EndConnect(IAsyncResult)方法将 抛出一个ObjectDisposedException到 表示操作已被取消 。

如果是做了BeginConnect的正确方法,它可能是因此对于BeginReceive为好。这当然是微软异步API的一个糟糕的设计,因为让用户必须抛出异常并捕获异常作为正常流程的一部分会让调试器恼火。在操作完成之前,你真的没有办法“等待”,因为Close()是首先完成它的东西。

+4

不能相信它是建立这样的工作,但这是我想的。 – Kelly 2012-03-30 20:05:38

+0

@凯利:作为一个设计它有什么问题?无论是否抛出异常,调用EndReceive的代码都需要处理失败。如果条件可以在`EndReceive`处理,不会抛出异常将允许`catch`替换为`if`,但如果它不能被处理,那么必须添加`如果([失败])抛出[某物]`并且仍然*需要捕获。对于使用异常与'if'有关的性能开销,不应该中断连接。 – supercat 2014-02-10 16:42:10

+4

由于抛出和捕获异常作为正常输入的一部分,而不是“特殊”流,这是一个糟糕的设计,无论性能如何。它也可能会在“break on throw”设置下烦扰调试,这通常很有用。 – 2014-02-12 14:27:33

-1

另一种解决方案是使用绑定到不同端口的套​​接字发送“自己”“控制消息”。这不完全是一个中止,但它会结束你的异步操作。

+0

他们也可以使用等待句柄或事件。他们也可以使用我在答案中指出的选项。这需要每个客户端和服务器有另一个套接字 – Jay 2014-12-29 09:10:32

-1

我一直在为此付出努力,但据我所知,在调用.BeginReceive()之前使用一个简单的布尔标志也可以工作(所以不需要异常处理)。由于我已经有了启动/停止处理,所以此修复程序是一个if语句的问题(向下滚动到OnReceive()方法的底部)。

if (_running) 
{ 
    _mainSocket.BeginReceive(_data, 0, _data.Length, SocketFlags.None, OnReceive, null); 
}     

我应该用这种方法忽略了一些东西,请告诉我!

2

我很惊讶没有人推荐使用SocketOptions。

一旦堆栈具有发送或接收操作,它将被套接字的套接字选项绑定。

使用一个小的发送或接收超时并在操作之前使用它,因此您不在乎在同一操作期间是否将其更改为更短或更长的操作。

这将导致更多的上下文切换,但不需要在任何协议下关闭套接字。

例如:

1)设置一个小的超时

2)执行操作

3)设置超时较大

这类似于使用阻塞= false,但用自动您指定的超时。

0

对于TCP套接字连接,您可以使用Connected财产试图访问之前确定套接字的状态任何处置方法。根据MSDN:

“Connected属性获取最后一次I/O操作的Socket连接状态,当它返回false时,Socket未连接,或者不再连接。

由于它表示“不再连接”,这意味着先前在套接字上调用了Close()。如果您在接收回调开始时检查套接字是否连接,则不会有任何异常。