c# - 发送大量 Protobuf 消息时 NetworkStream 关​​闭

标签 c# .net protobuf-net networkstream

我使用 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 destCanWrite 属性为 false。我的问题是:为什么 CanWrite 一段时间后从 true 变为 false?它是否与缓冲区溢出有关(因为我同时发送许多消息)?我该如何解决它?

编辑:

正如 @[Marc Gravell] 已经指出的那样,NetworkStream 已被释放,因此将 CanWrite 从 true 更改为 false。例如,如果我尝试访问 stream 对象的 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)
    ...

我仍在我的代码中寻找可能导致套接字被丢弃的内容。还有什么可能导致套接字在一段时间(几个小时)后被处理?

最佳答案

对于 NetworkStream,一点 IL 分析表明 CanWrite 遵循 m_Writeable。反过来,m_Writeable 通过三种方式变为 false:

  • 何时处置
  • 当使用 access 参数作为 FileAccess.Read 创建时
  • 当分配Writeable属性(protected)时(注意,我看不到框架中实际使用该属性的证据)

所以:如果您说这种情况发生在已经建立的 NetworkStream 上,并且已经运行了一段时间,那么最可能的答案是它在某个时候被处置,可能是由于被关闭

关于c# - 发送大量 Protobuf 消息时 NetworkStream 关​​闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19448237/

相关文章:

.net - 使用 RESTful WCF 和 Windows 窗体的用户/通过身份验证

c# - C# 中的 Protocol Buffer 和类型安全枚举

c# - protobuf-net:无法序列化类型数据,如何使用 Protocol Buffer 定义类型数据?

c# - 使用文本框搜索 ListView 项目

c# - C# ReaderWriteLock 中可升级读锁与写锁的区别

c# - byte[] 数组不能转换为 Base64 字符串吗?

c# - Protobuf-net:无法创建抽象类的实例

c# - 使用 C# 将单元格地址更改为 Excel 工作表中的行、列

c# - Xamarin EditText InputType 密码

.net - “IConfigurationSection”不包含 'Get' 的定义并且没有可访问的扩展名