从 .NET 中的 NetworkStream 读取的正确方法是什么

2023-12-01

我一直在努力解决这个问题,但找不到我的代码无法从我也编写的 TCP 服务器正确读取的原因。我正在使用TcpClient类及其GetStream()方法,但有些东西没有按预期工作。要么操作无限期地阻塞(最后一个读取操作没有按预期超时),要么数据被裁剪(由于某种原因读取操作返回 0 并退出循环,也许服务器响应速度不够快)。这是实现此功能的三种尝试:

// this will break from the loop without getting the entire 4804 bytes from the server 
string SendCmd(string cmd, string ip, int port)
{
    var client = new TcpClient(ip, port);
    var data = Encoding.GetEncoding(1252).GetBytes(cmd);
    var stm = client.GetStream();
    stm.Write(data, 0, data.Length);
    byte[] resp = new byte[2048];
    var memStream = new MemoryStream();
    int bytes = stm.Read(resp, 0, resp.Length);
    while (bytes > 0)
    {
        memStream.Write(resp, 0, bytes);
        bytes = 0;
        if (stm.DataAvailable)
            bytes = stm.Read(resp, 0, resp.Length);
    }
    return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}

// this will block forever. It reads everything but freezes when data is exhausted
string SendCmd(string cmd, string ip, int port)
{
    var client = new TcpClient(ip, port);
    var data = Encoding.GetEncoding(1252).GetBytes(cmd);
    var stm = client.GetStream();
    stm.Write(data, 0, data.Length);
    byte[] resp = new byte[2048];
    var memStream = new MemoryStream();
    int bytes = stm.Read(resp, 0, resp.Length);
    while (bytes > 0)
    {
        memStream.Write(resp, 0, bytes);
        bytes = stm.Read(resp, 0, resp.Length);
    }
    return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}

// inserting a sleep inside the loop will make everything work perfectly
string SendCmd(string cmd, string ip, int port)
{
    var client = new TcpClient(ip, port);
    var data = Encoding.GetEncoding(1252).GetBytes(cmd);
    var stm = client.GetStream();
    stm.Write(data, 0, data.Length);
    byte[] resp = new byte[2048];
    var memStream = new MemoryStream();
    int bytes = stm.Read(resp, 0, resp.Length);
    while (bytes > 0)
    {
        memStream.Write(resp, 0, bytes);
        Thread.Sleep(20);
        bytes = 0;
        if (stm.DataAvailable)
            bytes = stm.Read(resp, 0, resp.Length);
    }
    return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}

最后一个“有效”,但考虑到套接字已经支持读取超时,将硬编码的睡眠放入循环中确实看起来很难看!我是否需要在TcpClient of the NetworkStream?问题是否出在服务器上?服务器不会关闭连接,这取决于客户端。上面的内容也在UI线程上下文(测试程序)内运行,也许与此有关......

有人知道如何正确使用吗NetworkStream.Read读取数据直到没有更多数据可用?我想我想要的是旧的 Win32winsock 超时属性之类的东西......ReadTimeout等等。它尝试读取直到达到超时,然后返回0...但有时当数据应该可用时它似乎返回0(或者在途中..如果可用的话可以读取返回0吗?)并且它然后,当数据不可用时,在最后一次读取时无限期地阻塞...

是的,我很茫然!


众所周知,网络代码很难编写、测试和调试。

您经常需要考虑很多事情,例如:

  • 您将使用什么“字节序”来交换数据(Intel x86/x64 基于小字节序) - 使用大字节序的系统仍然可以读取小字节序的数据(反之亦然),但它们必须重新排列数据。在记录您的“协议”时,只需明确您正在使用哪一个即可。

  • 套接字上是否设置了任何可能影响“流”行为方式的“设置”(例如 SO_LINGER) - 如果您的代码非常敏感,您可能需要打开或关闭某些设置

  • 现实世界中导致流延迟的拥塞如何影响您的读/写逻辑

如果客户端和服务器之间(任一方向)交换的“消息”大小可能不同,那么您通常需要使用某种策略,以便以可靠的方式(也称为协议)交换该“消息”。

以下是处理交换的几种不同方法:

  • 将消息大小编码在数据之前的标头中 - 这可能只是发送的前 2/4/8 字节中的“数字”(取决于您的最大消息大小),或者可能是更奇特的“标头”

  • 使用特殊的“消息结束”标记(哨兵),如果实际数据可能与“标记结束”混淆,则对实际数据进行编码/转义

  • 使用超时......即在一定时间内没有接收到字节意味着该消息没有更多数据 - 但是,如果超时很短,这可能很容易出错,这很容易在拥塞的流上遇到。

  • 在单独的“连接”上有一个“命令”和“数据”通道......这是 FTP 协议使用的方法(优点是数据与命令清晰分离......以第二个连接为代价)

每种方法对于“正确性”都有其优点和缺点。

下面的代码使用“超时”方法,因为这似乎就是您想要的方法。

See http://msdn.microsoft.com/en-us/library/bk6w7hs8.aspx。您可以访问NetworkStream on the TCPClient所以你可以改变ReadTimeout.

string SendCmd(string cmd, string ip, int port)
{
  var client = new TcpClient(ip, port);
  var data = Encoding.GetEncoding(1252).GetBytes(cmd);
  var stm = client.GetStream();
  // Set a 250 millisecond timeout for reading (instead of Infinite the default)
  stm.ReadTimeout = 250;
  stm.Write(data, 0, data.Length);
  byte[] resp = new byte[2048];
  var memStream = new MemoryStream();
  int bytesread = stm.Read(resp, 0, resp.Length);
  while (bytesread > 0)
  {
      memStream.Write(resp, 0, bytesread);
      bytesread = stm.Read(resp, 0, resp.Length);
  }
  return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}

作为编写网络代码的其他变体的脚注......当做一个Read如果您想避免“阻塞”,您可以检查DataAvailable标志,然后只读取缓冲区中的内容检查.Length财产例如stm.Read(resp, 0, stm.Length);

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

从 .NET 中的 NetworkStream 读取的正确方法是什么 的相关文章

随机推荐

  • Android sqlite / BLOB 性能问题

    自从我将数据从 ArrayList 移动到 Android 上的 sqlite 数据库后 我的性能出现了严重下降 没有打开的游标可能会导致这种情况 因此我怀疑问题出在我存储在 BLOB 字段中的图像 该应用程序创建Cards有一个字段卡位图
  • 如何让 CMake 自动检测 CUDA_ARCHITECTURES 的值?

    较新版本的 CMake 3 18 及更高版本 了解 CUDA 代码编译目标的 CUDA 架构的选择 目标有一个CUDA ARCHITECTURES属性 设置后会生成适当的 gencode arch whatever code whateve
  • Java 安装程序 - 需要帮助[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心以获得指导 首先 您好 感谢您花时间帮
  • 使用Opencv提取图像的公共部分

    我正在编写一个程序来查找图像之间的差异 目前 我正在使用 AKAZE 寻找特征 因此我知道了这两张图像的共同点 问题是这两张图片只有一部分是共同的 如何从两幅图像中提取共同部分 为了更好的解释 我需要从第一张图像中提取公共部分 然后从第二张
  • 正则表达式以任意顺序匹配至少两个特殊字符

    我必须对密码进行 jQuery 表单验证 密码应至少包含两个特殊字符 任意顺序 我尝试过用于密码验证的正则表达式但它没有解决两个随机特殊字符可以按任意顺序出现的问题 如何使用 JavaScript 正则表达式来做到这一点 在不必要的情况下
  • asp.net mvc 中的 LINQ + EntityFunction

    我有这样的代码使用EntityFramework Alpha3 来自nuget class Member Key public int Key get set public string Forename get set public st
  • Scrapy递归下载内容

    敲了好几次头之后 我终于来到这里了 问题 我正在尝试下载每个 craiglist 帖子的内容 我所说的内容是指 发布正文 例如手机的描述 自 iPhone 以来寻找新的旧手机已经令人兴奋不已 该代码是一项很棒的工作迈克尔 赫尔曼 我的蜘蛛班
  • 错误:经典 ASP 的 ADODB 代码不支持参数类型

    我编写了插入调用用oracle pl sql 编写的参数化存储过程的代码 我已正确给出所有参数 如下面的代码所示 function CallSp str id ref no note userId strdatestamp writtenD
  • ASP.NET MVC 和混合模式身份验证

    我有一个场景 要求用户能够使用 Windows 身份验证或表单身份验证对 ASP NET MVC Web 应用程序进行身份验证 如果用户在内部网络上 他们将使用 Windows 身份验证 如果他们在外部连接 他们将使用表单身份验证 我看到很
  • 在pdo执行中多次分配相同的参数值

    我最初有一个SQL语句 是这样的 SELECT COUNT friend one AS pending count COUNT friend two AS requests sent FROM friends WHERE friend on
  • Spring Boot SAML 和 OKTA 的 SCIM 实现

    我的要求是为 Spring Boot 应用程序实现 SCIM 2 0 服务器 该应用程序支持 SAML 进行 OKTA 身份验证 我没有找到 Spring Boot 为 SCIM 服务器提供的任何库 并且 Spring 的 Repos 中也
  • MS Teams 机器人部署拒绝自动生成的 manifest.json,并显示消息“清单解析失败”

    我重新部署了我的 侧面加载的 Teams 应用程序 该应用程序实现了一个非常简单的机器人 每天自动向房间发送消息 这已经工作了很长时间 我做了一些细微的更改 因此我需要重新部署 从 Teams 房间中删除 然后将其添加回来 After I
  • 每个类别的 Holoviews 颜色

    我最近一直在使用散景来绘图 我刚刚发现全息视图并想绘制一个基本的箱形图 在我的箱形图中 我尝试为数据分组的每个类别着色 这是我正在使用的代码 hv extension bokeh opts BoxWhisker box color blue
  • 如何在 R 中的数据行内跨变量/向量查找众数

    有谁知道如何找到模式 R中单个案例的变量中最常见的模式 例如 如果我有关于最喜欢的水果类型 x 的数据 则对调查中的每个受访者 id 询问九次 x1 x9 如果我想找到每个测试对象在前五次询问中的模态响应 我将如何在 R 中进行编程 更简洁
  • 如果未找到行,则返回单行

    拥有我们用于 Crystal Report 的 T SQL 查询 SELECT COUNT AS Expr1 Date StoreNumber FROM dbo Orderp WHERE OpServerNumber 0 GROUP BY
  • Python - 类方法和 self 中的默认值

    我有以下类和方法 class Basis object def init self P dimension 1 generation 1 self P P self P angle np pi 4 where P is a dict这不包括
  • React Bootstrap OverlayTrigger 和 Tooltip 错误

    我试图在react bootstrap table的格式化程序中使用react bootstrap OverlayTrigger和Tooltip 并不断收到以下错误 OverlayTrigger 唯一需要的属性是 override 它应该是
  • 从内容 URI 获取目录路径

    我正在使用 SDKACTION OPEN DOCUMENT TREE意图让用户选择一个目录 这是代码 private static final int REQUEST PICK FOLDER 1 Override public boolea
  • 将路由值绑定到属于视图模型一部分的对象的属性

    我有以下路线 routes MapRoute Default Route name controller action id URL with parameters new controller Home action Index id P
  • 从 .NET 中的 NetworkStream 读取的正确方法是什么

    我一直在努力解决这个问题 但找不到我的代码无法从我也编写的 TCP 服务器正确读取的原因 我正在使用TcpClient类及其GetStream 方法 但有些东西没有按预期工作 要么操作无限期地阻塞 最后一个读取操作没有按预期超时 要么数据被