从关闭的 NetworkStream 读取不会导致任何异常

2023-12-27

我正在尝试创建一个相当简单的客户端服务器应用程序,但为了进行通信,我想使用二进制序列化对象。通信本身看起来相当不错,但是当我关闭客户端的流时,服务器并没有真正注意到它并继续尝试读取流。

服务器端(Server 类,在单独的线程中执行):

监听连接

listener = new TcpListener(IPAddress.Parse("127.0.0.1"), this.Port);
listener.Start();
while (!interrupted)
{
    Console.WriteLine("Waiting for client");
    TcpClient client = listener.AcceptTcpClient();
    AddClient(client);
    Console.WriteLine("Client connected");
}

添加客户端:

    public void AddClient(TcpClient socket)
    {
        Client client = new Client(this, socket);
        this.clients.Add(client);
        client.Start();
    }

监听消息(在 Client 类深处):

BinaryFormatter deserializer = new BinaryFormatter();
while (!interrupted)
{
    System.Diagnostics.Debug.WriteLine("Waiting for the message...");
    AbstractMessage msg = (AbstractMessage)deserializer.Deserialize(stream);
    System.Diagnostics.Debug.WriteLine("Message arrived: " + msg.GetType());
    raiseEvent(msg);
}

单元测试:

Server server = new Server(6666);
server.Start();

Thread.Sleep(500);

TcpClient client = new TcpClient("127.0.0.1", 6666);
var message = new IntroductionMessage();
byte[] arr = message.Serialize();

client.GetStream().Write(arr, 0, arr.Length);

Thread.Sleep(500);

Assert.AreEqual(1, server.Clients.Count);

client.GetStream().Close();
client.Close();

Thread.Sleep(1000);

Assert.AreEqual(0, server.Clients.Count);

server.Stop();

所以消息被正确读取,但是,当我关闭流时, deserializer.Deserialize(stream) 似乎不会抛出任何异常...所以应该不以这种方式读取,还是应该关闭客户端另一种方式?


假设服务器中用于反序列化消息的流是网络流 http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.aspx(这是返回的流的类型TcpClient.GetStream()),你应该做两件事:

  1. 为“连接结束”定义特定消息。当服务器接收并反序列化该消息时,退出 while 循环。为了实现这一点,客户端显然需要在关闭其 TcpClient 连接之前发送这样的消息。 (您可以选择以类似方式工作的不同机制 - 但为什么不使用您已有的消息机制......)

  2. Set a 读取超时 on the 网络流,因此,如果连接丢失并且客户端无法发送“连接结束”消息,服务器将超时并意识到客户端已“死亡”。

服务器中用于侦听客户端消息的代码应类似于以下内容:

//
// Time-out after 1 minute after receiving last message
//
stream.ReadTimeOut = 60 * 1000;

BinaryFormatter deserializer = new BinaryFormatter();

try
{
    while (!interrupted)
    {
        System.Diagnostics.Debug.WriteLine("Waiting for the message...");
        AbstractMessage msg = (AbstractMessage)deserializer.Deserialize(stream);
        System.Diagnostics.Debug.WriteLine("Message arrived: " + msg.GetType());

        //
        // Exit while-loop when receiving a "Connection ends"  message.
        // Adapt this if condition to whatever is appropriate for
        // your AbstractMessage type.
        //
        if (msg == ConnectionEndsMessage) break;

        raiseEvent(msg);
    }
}
catch (IOException ex)
{
    ... handle timeout and other IOExceptions here...
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从关闭的 NetworkStream 读取不会导致任何异常 的相关文章

  • 不同提供商的相同 EDMX 文件

    我正在开发一个项目 其中有一个本地数据库 SQL CE 在不存在与服务器的连接的情况下用作缓冲区 在服务器上我想使用相同的数据库布局 当然 我想使用服务器和客户端上可用的 Common dll 中的相同 EDMX 文件 在客户端中 我有一个
  • 使用sqlbulkcopy之前如何创建表

    我有一个 DBF 文件 我正在尝试导入该文件 然后将其写入 SQL 表 我遇到的问题是 如果我使用 SqlBulkCopy 它需要我提前创建表 但在我的场景中这是不可能的 因为 dbf 文件不断变化 到目前为止 这是我的代码 public
  • 成员字段、构建顺序

    在 C 中 当执行如下所示的操作时 构造顺序是否得到保证 Logger Logger kFilePath logs runtime log logFile kFilePath 是的 施工顺序始终得到保证 但是 不能保证它与对象在初始值设定项
  • C# 中直接从 URL 获取图像尺寸

    我正在尝试使用以下代码直接从网络上获取图片的尺寸 string image http www hephaestusproject com csharp3 png byte imageData new WebClient DownloadDa
  • 是否有可能将 *.pdb 文件包含到发布版本中以查看错误行号?

    我做了一个项目 所有设置都是默认的 当我在调试模式 构建配置 调试 下运行它并遇到异常时 它转储到我的自定义日志记录机制 其中包含错误行号 但是当我运行发布构建时 记录相同的异常 没有行号 只有方法抛出和记录调用堆栈 是否有可能在发布配置
  • std::bind2nd 和 std::bind 与二维数组和结构数组

    我知道 C 有 lambda 并且 std bind1st std bind2nd 和 std bind 已弃用 然而 从C 的基础开始 我们可以更好地理解新特性 所以 我从这个非常简单的代码开始 使用int 数组s 第一个例子 与std
  • 如何检查号码是否只有唯一的数字?

    例如 2345 是唯一的数字 因为没有数字显示两次 但 3324 不是唯一的数字 因为 3 出现了两次 我尝试使用 但我 代码 显示但我没有得到数字我得到了数字 编辑 你不能使用字符串 number 10 number 100 number
  • ASMX Web 服务,测试表单仅在本地计算机上适用于一种 WebMethod

    我有一个正在测试的 ASMX WebService 并且在大多数方法上我都可以使用测试表单进行测试 然而 我确实有一种方法 测试表上写着 The test form is only available for requests from t
  • 如何部署包含第三方 DLL 文件的 C# 应用程序?

    首先 我对部署了解不多 我希望我的问题有意义 我需要将 C 应用程序安装 部署到多个桌面 它需要一个第三方 DLL 文件 一个 C 库 lpsolve55 dll 对于那些感兴趣的人 它是一个免费的 MIP LP 求解器 请参阅 lpsol
  • 尽管浮点数相同,但它们并不相等? [复制]

    这个问题在这里已经有答案了 下面的程序输出This No is not same 当两个数字相同时为什么会这样做 void main float f 2 7 if f 2 7 printf This No is same else prin
  • 如何将 Visual-Studio 2010 切换到 c++11

    我是 c 编程新手 我想尝试 c 11 新功能 那么我要问的是如何切换 Visual studio 2010 才能编译 c 11 源代码 你可以参考这个表 VC10 中的 C 0x 核心语言功能 表格 http blogs msdn com
  • PartialView Action 正在调用自身

    我有 MVC 应用程序 它用于从主视图 ProductMaster 将 ProductAreaGrid 列表显示为 PartialView 并且它将在局部视图内将 CreateProductArea 作为 PartialView 我的 Gr
  • C#生成的csv文件通过电子邮件发送嵌入到Lotus Note中电子邮件的底部

    我遇到了一个奇怪的问题 即使用 NET SmtpClient 通过电子邮件发送的 CSV 附件出现在电子邮件底部 而不是 Lotus Note 中的附件 我只是不知道如何解决这个问题 而且我无法访问客户端计算机 这使得调试非常困难 我可以采
  • += 运算符在 C++ 中是如何实现的?

    这是我一直在思考的一个问题 但从未找到任何资源来说明这个问题的答案 事实上它不仅是为了 也适用于它的兄弟姐妹 即 等等 当然不是 考虑这个例子 int a 5 a 4 this will make a 9 现在考虑等效表达式 a a 4 T
  • 如何解决文件被另一个进程使用的问题?

    我一直在 VS NET 2010 中调试 没有任何问题 但现在无法建造 我收到错误 Unable to copy file filename to bin Debug filename The process cannot access t
  • 使用联合对 IP 地址进行多种解释?

    在工作中 我们使用以下构造来将 IP 地址解释为 4 字节数组或 32 位整数 union IPv4 std uint32 t ip std uint8 t data 4 这很好用 但是读完这本书的第 97 章 不要使用联合来重新解释表示
  • 如何在 ASP.NET Core 项目中使用 MStest 测试 Ok() 结果

    我正在使用 MStest 来测试我的控制器 我想测试这个动作 HttpGet Name GetGroups public async Task
  • 使用 WinAPI 连接禁用的显示设备

    我的问题是启用禁用的监视器ChangeDisplaySettingsEx 我想这不是火箭科学 但经过一番挖掘后 它看起来仍然是不可能的 我找到了一种根据找到的 Microsoft 代码示例禁用所有辅助显示器的方法here https msd
  • C# 模式匹配

    我对 C 有点陌生 我正在寻找一个字符串匹配模式来执行以下操作 我有一个像这样的字符串 该书将在 唐宁街 11 号接待处 并将由主要医疗保健人员参加 我需要创建一个 span 标签来使用 startIndex 和 length 突出显示一些
  • C# 和断点 - 这里有魔术师吗?

    我有这个 public static void ByLinkText string text for var i 0 i lt 50 i try Setup Driver FindElement By LinkText text Click

随机推荐