【问题标题】:TCP server not receiving all data being sentTCP 服务器没有接收到所有正在发送的数据
【发布时间】:2015-05-18 18:35:57
【问题描述】:

尝试设置 TCP 服务器以从流中获取数据。似乎正在工作,但仅在流较小时。一旦我开始发送大量数据,就会失败,只返回一部分字符。有谁可以帮我离开这里吗?为什么我只收到我发送的部分数据?

服务器的流程应该是,接收所有数据,存储到数据库 (RouteInboundXml()) 并开始监听更多传入数据。

private void ReceivePortMessages()
{
    string debug = string.Empty;
    try
    {
        Debug.Print(" >> Starting Server");
        IPAddress ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork);
        _TcpListener = new TcpListener(ipAddress, TcpPort); ;
        Debug.Print(string.Format("{0}:{1}", ipAddress.ToString(), TcpPort.ToString()));
        _TcpListener.Start();

        Stopwatch sw = new Stopwatch();
        do
        {
            try
            {
                _TcpClient = _TcpListener.AcceptTcpClient();
                Debug.Print(" >> Accept connection from client");
                NetworkStream networkStream = _TcpClient.GetStream();
                int receivingBufferSize = (int)_TcpClient.ReceiveBufferSize;
                byte[] bytesFrom = new byte[receivingBufferSize];
                int Read = 0;
                string dataFromClient = string.Empty;
                if (!sw.IsRunning)
                {
                    sw.Start();
                }
                Read = networkStream.Read(bytesFrom, 0, receivingBufferSize);
                dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
                dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("\0"));
                if (dataFromClient != string.Empty)
                {
                    XmlDocument xm = new XmlDocument();
                    debug = dataFromClient;
                    xm.LoadXml(string.Format("<root>{0}</root>", dataFromClient));
                    XmlElement root = xm.DocumentElement;
                    string rootName = root.FirstChild.Name;
                    RouteInboundXML(rootName, dataFromClient, sw);
                    sw.Restart();
                }
            }
            catch (Exception ex)
            {
                Debug.Print("ReceivePortMessages: " + ex.ToString());
                _TcpClient.Close();
                _TcpListener.Stop();
                ErrorLog.Write("XmlProcessing", ex.ToString() + "\r\n" + "DataFromClient: " + debug, "ReceivePortMessages()");
                return;
            }
        } while (true);
    }
    catch (Exception ex)
    {
        Debug.Print("ReceivePortMessages: " + ex.ToString());
        ErrorLog.Write("XmlProcessing", ex.ToString(), "ReceivePortMessages()");
    }
}

【问题讨论】:

  • 你有没有在调试模式下检查过dataFromClient的值?
  • @Ordenador 是的,它只返回了我发送的大约 70% 的内容。 xml 在中途被切断。

标签: c# xml tcp server tcpserver


【解决方案1】:

您似乎希望每次调用Stream.Read 时都会收到完整的XML 文档——并且准确地是XML 文档。这是一个非常非常危险的假设。

流是数据流 - 虽然它会被分割成数据包进行传输,但您不应期望在与Write 调用相同数量的Read 调用中接收数据。


每个连接的单个文档的详细信息

如果每个流只有一个文档,您可能可以大大简化代码使其正常工作。只需使用接受流的XmlDocument.Load 的重载这一事实:

using (var tcpClient = tcpListener.AcceptTcpClient())
{
    XmlDocument doc = new XmlDocument();
    using (var stream = tcpClient.GetStream())
    {
        doc.Load(stream);
    }
    // Use doc here
}

(如果可以的话,我个人会开始使用 LINQ to XML,但那是另一回事。)


多个文档的详细信息

如果您希望单个 TCP 流上有多个消息,您应该实现某种“分块”协议。这样做的一种好方法是将每条消息拆分为“标题”和“正文”,其中标题可能与“正文中的字节数”一样简单,因此您知道要阅读多少。 (或者,您可以为标头设计协议以包含其他元数据。)

读取标头后,您从流中读取正文,直到您读取的字节数与标头中指示的字节数一样多,或者到达流的末尾(这通常表示错误)。这可能需要多次Read 调用。 然后您处于将数据解析为 XML 文档的合适位置 - 理想情况下,无需先进行自己的二进制/文本解码,因为并非所有 XML 都是 ASCII...

可以以这样一种方式设计您的协议,即您只需在消息之间设置一个分隔符 - 但这通常更难实现,因为它混合了“读取数据”和“理解数据” ”。如果您可以改用上述长度前缀方案,那就简单多了。

【讨论】:

  • 感谢Jon 的回复,我无法控制传入的xml,所以我的手在这里有些束缚。对于不想更改其设置的客户,我必须与另一个系统集成。你有没有在你的头顶上提到任何我冷眼旁观的特别之处?这对我来说是一个特别困难的概念(出于某种原因),我很难理解它是如何工作的。
  • @Volearix:在一个流中肯定有多个 XML 文档吗?如果没有长度前缀或类似的,则每个连接都有一个文档更为常见。 (实际上,我想我误读了您的代码...如果您只期望一个文档,那会简单得多。将编辑...)
  • 据我所知,每个连接应该只有一个 xml 文档。
  • @Volearix:查看我的编辑。使用 XML 解析器已经知道如何处理流的事实......
  • doc.Load(stream); 似乎只是挂起。不抛出错误,而是挂起。
【解决方案2】:

这是我过去使用的一些代码。 对我有用。

using (TcpClient client = new TcpClient(ip, port))
{
    var stm = client.GetStream();
    stm.Write(data, 0, data.Length); //Write some data to the stream

    byte[] resp = new byte[1024];
    var memStream = new MemoryStream();
    var bytes = 0;
    client.Client.ReceiveTimeout = 200;

    do
    {
        try
        {
            bytes = stm.Read(resp, 0, resp.Length);
            memStream.Write(resp, 0, bytes);
        }
        catch (IOException ex)
        {
            // if the ReceiveTimeout is reached an IOException will be raised...
            // with an InnerException of type SocketException and ErrorCode 10060
            var socketExept = ex.InnerException as SocketException;
            if (socketExept == null || socketExept.ErrorCode != 10060)
            // if it's not the "expected" exception, let's not hide the error
            throw ex;
            // if it is the receive timeout, then reading ended
            bytes = 0;
        }
    } while (bytes > 0);

    return memStream.ToArray();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-28
    • 1970-01-01
    • 1970-01-01
    • 2017-12-28
    • 2012-06-29
    • 1970-01-01
    • 2019-05-27
    相关资源
    最近更新 更多