【问题标题】:HTTP request over GPRS and TCP dropping packets通过 GPRS 和 TCP 丢弃数据包的 HTTP 请求
【发布时间】:2017-10-17 16:17:11
【问题描述】:

我正在为通过 GPRS 连接的生物识别指纹设备编写服务器。服务器从设备接收 GET 和 POST 请求,然后执行所需的操作。

对于 POST 请求,设备应在请求中附加一些附加数据。

问题是,当我通过 LAN 将设备连接到服务器时,所有数据都可以正常通过。当我通过 GPRS 连接时,我的服务器没有接收到请求正文。

左边是我通过 LAN 连接时...附上邮件正文。右边,是通过GPRS,一切照旧,但是,没有body。

我通过 LAN 和 GPRS 连接运行 Wireshark。当我向下钻取时,这些数据包都附有正文,但在 Wireshark 上,通过 GPRS,我收到类似上面的消息 - 出现故障和 RST、ACK 以及有时是 PSH、ACK。

与 LAN 数据包相比,没有这些问题。

这是我用来从 TCPListener 读取的代码

try
  {
    if (tcp == null)
    {
       this.tcp = new TcpListener(IPAddress.Parse(serverIP), port);
    }
    this.tcp.Start();
    listening = true;

    while (listening)
    {
        Socket mySocket = null;

        // Blocks until a client has connected to the server
        try
        {
           mySocket = this.tcp.AcceptSocket();
           Thread.Sleep(500);

           byte[] bReceive = new byte[1024 * 1024 * 2];
           mySocket.Receive(bReceive);

           Analysis(bReceive, mySocket);
        }
        catch(Exception ex)
        {
           MessageBox.Show(ex.Message);
        }
    }

   this.tcp.Stop();

这是我从他们的开发者那里得到的原始代码。我尝试了异步、TcpClient 和不同套接字选项(例如 KeepAlive 和 DontLinger)的各种组合,但似乎没有一个能解决这个问题。

除了在 C# 中手动捕获数据包以获取正文之外,是否有任何 C# 类可以用来读取整个请求?

【问题讨论】:

  • 您在两次捕获中都获得了 200 OK,这意味着 HTTP 层工作正常。在第二个你有 [FIN, ACK] 这是连接关闭的 ACK。所以 172.31.168.217 是发送关闭确认。看起来 FIN(完成)继续发生。我会找出 FIN 发生的原因。
  • 我会摆脱睡眠并使用来自 msdn 的代码:msdn.microsoft.com/en-us/library/fx6588te(v=vs.100).aspx
  • @jdweng 您是否认为乱序消息与此有关?谢谢你的链接,我试试看。
  • 可能的。乱序本身不会引起问题。它可能表示由于硬件故障而丢弃了数据包,但 PC 中的驱动程序会重新排序数据包。我认为该软件在不应该关闭连接时关闭了连接。同样,这可能是硬件问题,但不是决定性的。我认为正确的做法是找出第一个 FIN 发生在哪里。我还想看看是否有任何 SEQ 由于退休而重复。我不知道您对 TCP 规范和 c# 代码的理解程度如何。我是个专家。从事 TCP 测试 5 年。
  • @jdweng 我不明白的是,即使数据包被丢弃并且软件可能正在关闭连接,WireShark 仍然可以重组数据包并获取我正在寻找的数据,但在 C# 中我不能。

标签: c# rest sockets networking tcp


【解决方案1】:

TCP 是一种面向流的协议。大家都知道,但是很多开发者在实现 TCP 接收器时并没有考虑到这一点。

当发送调用Send("ABCDEFG") 和客户端调用Receive(buffer) 时,buffer 可能包含"ABCDEFG""ABCD""A" 或原始数据中以"A" 开头的任何子字符串。 TCP 是一个没有任何消息边界信息的数据流。

需要在编译期间接收长度未知的消息(如 HTTP 请求)的接收器必须包含一个逻辑来接收标头、解析它并等待直到收到完整的消息。

但您不需要自己实现它。 C# 具有已包含此逻辑的类HttpServer。此外,还有一些支持 REST 的库。它正在重新发明轮子来实现一个 REST 服务器并从 TcpListener 和套接字开始。

【讨论】:

  • 感谢您的信息。我尝试使用 HttpListener 类,但它似乎不想在 LAN 上工作,我的软件必须支持 LAN 和 GPRS。通过 GPRS,我使用 URI 连接到服务器,在 LAN 上,我通过 IP 地址连接到服务器。我想不出如何解决 TCPListener 采用 IP 地址和 HttpListener 采用 URI 的事实,而且它们似乎是互斥的。但是,正如你所说,我确实觉得我在尝试重新发明轮子。我会尝试你的建议。
  • HttpServer 类不依赖于物理层,它可以与 LAN、GPRS 以及任何类型的物理网络正常工作。创建它时,您需要指定服务器侦听的端口,并且它侦听主机拥有的所有接口。
  • 好的,谢谢您的建议。请参阅我对 jdweng 的第二条评论 - 我认为归根结底,这是我最关心的问题...如果正在发送数据包,为什么没有 C# 类执行重组?
  • TCP 不是用于传递数据包的服务。它是流服务。因此 C# 套接字无法执行重组,因为 TCP 没有消息/数据包边界之类的东西。好吧,在较低层有数据包,但它们对 TCP 应用程序不可见。应用程序级协议必须从流中重组消息,HttpServer 类会这样做。
【解决方案2】:

我最终使用下面链接中的代码将服务器实现为异步。这样我就可以实现逻辑以在未到达流末尾时重新读取流。我只需要根据我的情况更改文件结束条件。

这是文章的链接:

https://docs.microsoft.com/en-us/dotnet/framework/network-programming/asynchronous-server-socket-example

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-20
    • 1970-01-01
    • 2018-09-04
    • 2012-08-18
    • 1970-01-01
    • 1970-01-01
    • 2016-01-14
    相关资源
    最近更新 更多