我使用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 回答
对于
NetworkStream
,一点IL分析显示CanWrite
延迟到m_Writeable
. 反过来,m_Writeable
在三个方面变为false
:何时被处置
在使用
access
参数创建FileAccess.Read
时当
Writeable
属性(protected
)被分配时(我看不到该属性实际上在框架中使用的证据,请注意)所以:如果你说这种情况发生在已经 Build 好的
NetworkStream
已经很好的一段时间了,那么最可能的答案是它在某个时候被处理掉了,可能是因为被关闭了也许你正在耗尽服务器的TCP / IP端口?
您没有提到您的服务器正在运行哪个操作系统,但假设它是2008服务器,您有appx 16000可用端口(49152-65535) . 关闭连接时,端口将保持TIME_WAIT状态4分钟,然后再次可用 . 这意味着如果您在不到4分钟内有超过16000个连接,您的服务器将开始拒绝连接 .
遇到错误时,请尝试在服务器上运行此命令:
netstat.txt中的行数告诉您已 Build 或time_wait状态的TCPv4连接数 .
你可以调整一下 . 通过增加动态端口数量,减少time_wait间隔或两者 .
要查看您的实际值:
一些有用的资源:
Port Exhaustion and You (or, why the Netstat tool is your friend)
How to tune the TCP/IP stack for high volume of web requests
Avoiding TCP/IP Port Exhaustion
The default dynamic port range for TCP/IP has changed in Windows Vista and in Windows Server 2008