最近我写的一个客户端程序出了问题,即很多用户同时掉线时(例如在打开很多客户端的电脑上拔掉网线),有很小的概率服务器会出现异常。异常的Trace显示,这是对已经关闭的TcpClient写入数据时导致的。具体是调用NetworkStream.BeginWrite方法时,出现InvalidOperationException,消息是“写操作不支持”。而这个异常甚至没有在BeginWrite的MSDN文档中出现。
我查看了一下代码,主要原因是很多用户同时掉线,很可能同时出现心跳停止。在用户退出时,会向所有其他用户发送通知消息。这时,如果一个用户退出时向其他用户发送消息,而那个用户正好也在退出,其TcpClient已经关闭,向其NetworkStream发送消息时就会出问题:出现开始所说的异常。(概率小的原因在于,一切都发生在几个调用之间)
解决方法,即TcpClient关闭时,也要手工关闭从其获得的NetworkStream(调用Close方法)。这时,如果还有调用,则会出现ObjectDisposedException,而这个异常是捕获的。所以,解决这个问题所做的改动就是在底层公共通信库里添加一句:m_stream.Close()。一切正常了!
后来看MSDN,微软也说,NetworkStream必须随TcpClient一起关闭,关闭TcpClient并不代表NetworkStream也关闭了。写C#网络程序的引以为戒。