【问题标题】:C# Threaded messages with TcpClient (various errors)带有 TcpClient 的 C# 线程消息(各种错误)
【发布时间】:2014-10-21 13:25:21
【问题描述】:

我需要通过 TCP 连接发送 500 条消息,并在有限的时间内接收每条消息的响应,并使用线程保持在该时间内。这对我来说是新的,在我把它放在这里之前我花了很多时间搜索论坛,所以请耐心等待。

到目前为止,我得到的最好结果是:

List<Task> tasks = new List<Task>();
for(int i=1;i<500;i++)
{
    Task task = new Task(new SendMessage(Message(i)).Send);
    tasks.Add(task);
}

然后

foreach(Task task in tasks)
{
    task.Start();
}

// Keep track of time (stay within 30s)
Stopwatch s = new Stopwatch();
s.Start();
while (s.ElapsedMilliseconds < 30000)
{
    Console.WriteLine((int)(0.001 * s.ElapsedMilliseconds));
    Thread.Sleep(2000);
}

然后

public class SendMessage
{
    byte[] msg;
    ASCIIEncoding asen = new ASCIIEncoding();
    NetworkStream stm;

    public void Send()
    {
        try
        {
            TcpClient tcpclnt = new TcpClient();

            tcpclnt.Connect("IPADDRESS", port);

            stm = tcpclnt.GetStream();

            stm.Write(msg, 0, msg.Length);

            using (XmlReader xmlReader = XmlReader.Create(stm))
            {
                while (xmlReader.Read())
                {
                    string requestID = String.Empty;
                    string message = String.Empty;

                    if ((xmlReader.NodeType == XmlNodeType.Element) && (xmlReader.Name == "requestID"))
                    {
                        requestID = xmlReader.ReadInnerXml();
                        sw.Write("requestID\t" + requestID + "\t");
                        Console.WriteLine("requestID\t" + requestID + "\t");
                    }
                    else if ((xmlReader.NodeType == XmlNodeType.Element) && (xmlReader.Name == "message"))
                    {
                        message = xmlReader.ReadInnerXml();
                        sw.WriteLine("message\t" + message);
                        Console.WriteLine("message\t" + message);

                        xmlReader.Close();
                    }
                }
            }
        }
        catch
        {
            Send();
        }
    }
    public SendMessage(  string msg)
    {
        this.msg = asen.GetBytes(msg);  
    }
}

但应用程序在阅读部分不断崩溃。我在这个例子中得到的错误是

XMLException - 缺少根元素

try/catch 块似乎可以工作,但错误如此频繁,以至于它会减慢应用程序的速度,以至于我无法将时间消耗保持在可接受的范围内。

我尝试过的变体

  1. 使用全局静态 TCPClient 在 Main 而不是在 Send() 中连接
  2. 在 SendMessage 中使用全局或本地 NetworkStream
  3. 将 TCPClient 作为参考
  4. 使用线程而不是任务
  5. 使用其他线程安全读取器类型(使用线程时)

【问题讨论】:

  • 您遇到了什么问题,您解释了您在做什么并向我们展示了您尝试过的内容,但您错过了您尝试过的问题。请edit your question 添加有关您遇到的错误或不正确行为的详细信息。
  • 你可能也想删除IP地址
  • 我会选择异步套接字 IO,最好使用现有的 TCP/IP 基础设施(例如 WCF 或 Protobuf)。网上有很多关于如何做到这一点的示例......正确实现套接字可能很棘手,因此重新发明轮子没有什么意义。
  • 还有。您的 try catch 不会减慢您的应用程序的速度。它是您生成的 500 个线程..
  • 捕获经常遇到错误(缺少 XML 根元素)并重新发送消息 - 我认为 - 非常耗时。

标签: c# multithreading


【解决方案1】:

在 TCP 连接中,您可以同时向套接字发送和接收,但不能从多个线程分别发送或接收。

最好使用生产者/消费者模式,这样您无需等待即可发送并在消息到达时收到通知:How to: Implement a Producer-Consumer Dataflow Pattern

此外,您需要一些框架协议来通过套接字发送内容,让另一端知道消息从哪里开始或结束。这就是为什么缺少文件的一部分。

我建议你看看 WCF:Windows Communication Foundation [.NET Framework 4.0]

【讨论】:

    【解决方案2】:

    我相信您遇到的问题是您在从流中读取之前没有等待响应。 The accepted answer here shows how to wait for a response before reading. 虽然还有其他复杂性需要考虑,但这应该可以解决您当前的问题。如果您的消息很大(超过 ~1.5 KB,或您的默认 mtu 大小),仅仅因为您在套接字上收到了一些数据,并不意味着您已经在套接字上收到了所有数据。因此,您需要为您的 XML 响应提供某种框架。这导致了另一个答案,您是否考虑过研究 WCF 或 Web 服务生产者/消费者?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-05
      • 2011-02-27
      相关资源
      最近更新 更多