【问题标题】:BeginReceive / BeginRead timeoutsBeginReceive / BeginRead 超时
【发布时间】:2011-03-28 20:05:01
【问题描述】:

我正在使用 NetworkStream 和 TcpClient 通过 BeginRead 异步接收数据。我需要对此操作应用超时,这样在指定的时间后读取将被中止。

据我所知,NetworkStream 或 TcpClient 不支持此功能 - 有一个 ReceiveTimeout 属性,但这似乎仅适用于同步等效项 - 'Read'。

甚至底层的 Socket 类似乎也不支持其 BeginReceive 方法中的超时。

我已经搜索过这个问题并且我看到的唯一建议的解决方案是设置另一个后台线程以取消操作,如果它没有在超时期限内完成。这似乎是一个可怕的黑客攻击。肯定有更好的方法吗?

【问题讨论】:

    标签: asynchronous tcpclient networkstream beginreceive beginread


    【解决方案1】:

    这是唯一的方法,因为当您使用异步操作时,启动该操作的线程正在执行其他操作。同步版本可以使用超时,因为执行线程被阻塞,直到读取操作完成。

    如果您必须使用后台线程来取消操作,那么继续使用异步 Begin/End 方法就没有多大意义了。如果要分离后台线程,只需从后台线程执行同步读取操作,然后就可以使用 ReceiveTimeout。

    【讨论】:

    • Joel 为我们指出了正确的方向,即不使用后台线程来取消,但如果不是很明显,很多人所做的是定期拥有 1 个线程(可能来自工人投票)清理死连接。这是释放套接字句柄/等所必需的,如果您遇到诸如拒绝服务攻击之类的事情(无论是否有意),这一点尤其重要。
    • 另一个选项是System.Threading.Timer,不占用线程。
    • @hangar Timer 有 4 个实现,System.Threading.Timer 确实占用了一个线程,它只是在线程池上运行,因此您不必手动管理拥有计时器所需的资源功能。 docs.microsoft.com/en-us/dotnet/api/…
    【解决方案2】:

    等待ManualResetEvent 带有一些超时值,以便在您的任务完成时发出信号。如果它在发出信号之前超时,那么您就知道异步操作从未完成。

    private ManualResetEvent receiveDone = new ManualResetEvent(false);
    
    receiveDone.Reset();
    socket.BeginReceive(...);
    if(!receiveDone.WaitOne(new TimeSpan(0, 0, 0, 30))) //wait for 30 sec.
        throw new SocketException((int)SocketError.TimedOut);
    

    在 BeginReceive 回调中,使用

    private void ReceiveCallBack(IAsyncResult ar)
    {
        /** Use ar to check if receive is correct and complete */
        receiveDone.Set();
    }
    

    【讨论】:

    • 投反对票,因为这正是我(天真地)所做的,但它不起作用。每次调用BeginReceive 与调用EndReceive 不匹配都会泄漏内核资源。在 Perfmon 之类的东西中绘制进程活动图并观察非分页池 慢慢地 泄漏。如果这持续足够长的时间(在我的情况下是几个小时),你最终会得到一个错误代码为WSAENOBUFS 的异常; “由于系统缺少足够的缓冲区空间或队列已满,无法对套接字执行操作。”
    • 我还没有验证它,但我们不能通过在抛出异常之前调用socket.EndReceive(..) 来解决您的问题吗?调用“EndReceive”所需的 IAsyncResult 由 BeginReceive 返回。支持您的评论。感谢您的更新。
    • 所以...毕竟不是异步操作。我的意思是,使用 BeginReceive 有什么意义,你阻塞线程直到超时?只需使用带有套接字超时的同步操作..
    猜你喜欢
    • 2011-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-21
    • 1970-01-01
    相关资源
    最近更新 更多