【问题标题】:TCP Client - Data gets corrupted only in some partsTCP 客户端 - 数据仅在某些部分损坏
【发布时间】:2015-12-26 07:43:21
【问题描述】:

我有一个将文件发送到服务器的客户端应用程序。问题是在客户端部分文件被正确读取,我可以在读取后再次保存字节数组并将其保存为有效的 jpg。然而,在服务器端,数据在某些地方会损坏。我所做的就是不断将所有传入数据添加到列表中,直到客户端关闭连接。

我重叠了发送/接收的客户端和服务器数据,如您所见,有些地方数据不匹配:http://s16.postimage.org/mtmm1hssl/corrupted_data.png

我不明白这怎么可能,我正在使用一个大缓冲区并且图像相当小,所以即使服务器以一个“块”接收图像,数据仍然损坏。

任何想法为什么会发生这种情况?

更新:

客户方:

我正在使用 HttpWebRequest 获取图像:

                  List<byte> test_buffer = new List<byte>();

                  using (Stream MyResponseStream = hwresponse.GetResponseStream())
                  {
                      byte[] MyBuffer = new byte[4096];
                      int BytesRead;

                      while (0 < (BytesRead = MyResponseStream.Read(MyBuffer, 0, MyBuffer.Length)))
                      {

                          for (int i = 0; i < BytesRead; i++)
                          {
                              test_buffer.Add(MyBuffer[i]); // just for testing
                          }

                          TCP_R.SendBytes(MyBuffer); // send data back to server
                      }
                  }

                  TCP_R.Close(); // tell server that we're done sending data

TCP_R 是一个处理所有 TCP 东西的类(连接到服务器/发送数据)

这是 TCP_R.SendBytes 函数:

    public void SendBytes(Byte[] data)
    {
        try
        {
            if (m_clientSocket != null)
            {
                m_clientSocket.Send(data);
            }

        }
        catch (SocketException se)
        {
            log("send_bytes err: " + se.Message);
        }
    }

请注意,我使用 test_buffer 收集所有字节以验证是否正确接收所有内容。如果我使用此代码:

                  MemoryStream ms = new MemoryStream(test_buffer.ToArray());
                  Image returnImage = Image.FromStream(ms);
                  returnImage.Save("image.jpg");

图像创建成功。所以我假设客户端正确发送数据。

服务器端:

我使用 OnDataReceived 函数收集数据并在 REQUEST_RESPONSE 中构建所有数据,即List&lt;byte&gt;

  public void OnDataReceived(IAsyncResult asyn)
    {

        try
        {
            SocketPacket socketData = (SocketPacket)asyn.AsyncState; // cast

            int iRx = 0;

                iRx = socketData.m_currentSocket.EndReceive(asyn);
                char[] chars = new char[iRx + 1];

                System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder(); // CAN THIS BE CAUSING THE PROBLEM!?!
                int charLen = d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);


                for (int s = 0; s < charLen; s++)
                {

                    RESPONSE_DATA.Add(socketData.dataBuffer[s]); // Collect response data

                }

                WaitForData(socketData.m_currentSocket, socketData.socket_id, REQUEST_INDEX_ID);

            }

        }
        catch (ObjectDisposedException)
        {

        }
        catch (SocketException se)
        {

        }
    }

更新 2: 看来是这些行导致了问题:

                System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder(); // CAN THIS BE CAUSING THE PROBLEM!?!
                int charLen = d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);

如何在不使用解码器的情况下将数据提取到 socketData.dataBuffer 中?

解决方案: 即使我直接从 dataBuffer 读取,'d.GetChars(socketData.dataBuffer..' 行以某种方式搞砸了缓冲区,因此我搞砸了数据。我仍然需要使用 GetChars 来将数据包的第一部分作为字符串读取所以我只是改变了:

 int charLen = d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);

到:

 byte[] tmp_a = new byte[socketData.dataBuffer.Length];
 tmp_a = socketData.dataBuffer;
 int charLen = d.GetChars(tmp_a, 0, iRx, chars, 0);

现在一切顺利。显然以某种方式直接在缓冲区上调用 getChars 会影响缓冲区。

【问题讨论】:

  • 给我们看一些代码。如果您遗漏所有细节,您就不能指望我们回答这个问题。
  • 我怀疑您的代码有问题,无论是在客户端还是服务器上。不幸的是,您既没有向我们展示客户端代码,也没有向我们展示服务器代码,这让我们很难分辨...
  • 需要查看您的代码...发送和接收。
  • 我们需要查看执行接收的代码,尤其是读取/接收循环,以及它如何处理读取/接收的返回值,以及它在哪里处理计数/偏移量。如果这些听起来都不熟悉,那么肯定是问题所在。
  • @user1192403 回复您的“我该怎么办?”问题:这就是 Receive 所做的。 GetChars 正在读取 缓冲区

标签: c# tcpclient


【解决方案1】:

听起来像是编码问题。

这里的关键概念是编码是针对文本的,而图像不是文本。

不要在发送前或接收后尝试对字节进行编码或解码。

同样,如果您从文件读取或写入图像,请不要尝试编码或解码,使用二进制模式。

只是不要尝试将字节转换为字符,这样做没有任何意义。

【讨论】:

  • 纯属猜测。特别是,通过 tcp 发送原始二进制数据不应涉及任何编码。
  • 这个问题除了推测之外没有其他用途。
  • 是的,它不应该涉及任何编码,这就是为什么我认为编码可能是问题所在。
  • 塞缪尔,我认为你是对的。你能检查我的服务器端代码吗,我在那里得到了 UTF8,如何在不使用 UTF8 编码的情况下获取缓冲区中的所有字节!?
  • @user1192403 你到底为什么要使用文本处理? Jpg 不是文本数据。您应该为此使用原始字节 []。根本没有“char”。
猜你喜欢
  • 2015-09-21
  • 2023-04-06
  • 1970-01-01
  • 2016-10-05
  • 1970-01-01
  • 2011-09-25
  • 1970-01-01
  • 2019-05-24
  • 1970-01-01
相关资源
最近更新 更多