首页 文章

发送许多Protobuf消息时NetworkStream关闭

提问于
浏览
2

我使用protobuf-net和.NET的TCPClient和NetworkStream进行一个服务器和许多客户端之间的通信 . 对于发送消息,我在两侧使用以下方法:

public static bool WriteProtocolBufferToStream(System.IO.Stream stream, object protoBufObject)
    {            
            // ... check parameters ...                
            // ... Determine the 'fieldNumber' of the 'protoBufObject' via a helper dictionary ...  
            if (fieldNumber > -1)
            {
                try { Serializer.NonGeneric.SerializeWithLengthPrefix(stream, protoBufObject, ProtoBuf.PrefixStyle.Base128, fieldNumber); }
                catch (Exception ex)
                {
                    Logger.Instance.Error("Exception: " + ex.Message);
                    return false;
                }
            }
            else
            {
                Logger.Instance.Error("unknown message type");
                return false;
            }
            return true;            
    }

在只有一些客户端和少量消息的小场景中,一切都很好 . 但是在有大约40个客户端和许多交换消息的场景中我遇到了问题 . 消息非常小(包含1到5个小字符串),但服务器可能同时发送多个(最多200个)这些消息 .

一段时间后(几分钟到几个小时)抛出以下异常:

ArgumentException: Cannot write to stream. Parameter name: dest

源是protobuf-net的ProtoWriter类构造函数 . 它抛出此异常,因为 NetworkStream dest的 CanWrite 属性为false . 我的问题是:为什么 CanWrite 会在一段时间后从true变为false?它是否与溢出缓冲区有关(因为我同时发送了许多消息)?我该怎么办呢?

EDIT:

正如@ [Marc Gravell]已经指出的那样, NetworkStream 被释放,因此将 CanWrite 从true更改为false . 如果我试图访问流对象的 WriteTimeout 属性,我得到这个:

System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
    at System.Net.Sockets.Socket.GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName)
    at System.Net.Sockets.NetworkStream.get_WriteTimeout()
    at Utilities.CommunicationHelper.WriteProtocolBufferToStream(NetworkStream stream, Object protoBufObject)
    ...

我仍在寻找代码中的某些内容,这可能导致Socket的处理 . 还有什么可能导致Socket在一段时间(几个小时)后丢弃?

2 回答

  • 2

    对于 NetworkStream ,一点IL分析显示 CanWrite 延迟到 m_Writeable . 反过来, m_Writeable 在三个方面变为 false

    • 何时被处置

    • 在使用 access 参数创建 FileAccess.Read

    • Writeable 属性( protected )被分配时(我看不到该属性实际上在框架中使用的证据,请注意)

    所以:如果你说这种情况发生在已经 Build 好的 NetworkStream 已经很好的一段时间了,那么最可能的答案是它在某个时候被处理掉了,可能是因为被关闭了

  • 0

    也许你正在耗尽服务器的TCP / IP端口?

    您没有提到您的服务器正在运行哪个操作系统,但假设它是2008服务器,您有appx 16000可用端口(49152-65535) . 关闭连接时,端口将保持TIME_WAIT状态4分钟,然后再次可用 . 这意味着如果您在不到4分钟内有超过16000个连接,您的服务器将开始拒绝连接 .

    遇到错误时,请尝试在服务器上运行此命令:

    netstat -p TCP -ano > netstat.txt
    

    netstat.txt中的行数告诉您已 Build 或time_wait状态的TCPv4连接数 .

    你可以调整一下 . 通过增加动态端口数量,减少time_wait间隔或两者 .

    要查看您的实际值:

    • Time_wait(TcpTimedWaitDelay)(默认值为240,如果未找到该值,则为4分钟)
    reg query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\TcpTimedWaitDelay
    
    • 动态端口范围:
    netsh int ipv4 show dynamicportrange tcp
    

    一些有用的资源:

相关问题