【问题标题】:TCP Listener stops listening after some timeTCP 侦听器在一段时间后停止侦听
【发布时间】:2019-10-20 15:17:48
【问题描述】:

我目前使用 c#.net windows 窗体开发一个 TCP 侦听器。它似乎在一段时间后停止侦听,当客户端随后发出请求时它不侦听。不抛出异常。

namespace WindowsTCPListener
{
    public partial class Form1 : Form
    {
        TcpListener listener;
        public Form1()
        {
            InitializeComponent();
            Thread t = new Thread(() =>
            {             
                ListenTCPPort();   
            });
            t.Start();
        }

        public void ListenTCPPort()
        {
            string ipAddress, portNumber, mqName;
            ipAddress = ConfigurationManager.AppSettings.Get("IP").ToString().Trim();
            portNumber = ConfigurationManager.AppSettings.Get("PORT").ToString().Trim();
            mqName = ConfigurationManager.AppSettings.Get("MSMQ").ToString().Trim();
            int j;
            int port = Int32.TryParse(portNumber, out j) ? j : 0;
            IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ipAddress.ToString()), port);
            listener = new TcpListener(ep);
            listener.Start();

            try
            {
                this.listBox1.Items.Add("Started listening requests at: " + ipAddress.ToString() + ":" + portNumber.ToString());          
            }
            catch (Exception) {}

            while (true)
            {
                try
                {
                    const int bytesize = 1024 * 1024;
                    string message = null;
                    byte[] buffer = new byte[bytesize];

                    TcpClient sender = listener.AcceptTcpClient();

                    sender.GetStream().Read(buffer, 0, bytesize);


                    message = cleanMessage(buffer);

                    byte[] bytes = System.Text.Encoding.Default.GetBytes(message);

                    string data = System.Text.Encoding.Default.GetString(bytes);

                    try
                    {


                        this.listBox1.Items.Add("Incoming : " + data.ToString());
                    }
                    catch (Exception) {}

                    string output = sendMessage(data, sender, mqName);
                    this.listBox1.Items.Add(output);
                    sender.Close();

                }
                catch (Exception e)
                {
                    try
                    {
                        this.listBox1.Items.Add("Exception : " + e.ToString());
                    }
                    catch (Exception) { }
                }
            }
        }
    }
}

【问题讨论】:

  • 可能没有直接关系,但不要这样做:catch (Exception) {}。至少记录异常。
  • 你能打印出你收到的所有异常吗?
  • “当客户端随后发出请求时” 客户端是重新连接还是仅在同一个连接上发送(在第一次之后将关闭)?
  • 顺便说一句:您正在从非 UI 线程修改 UI 元素。那就麻烦了。
  • 我不会在非 UI 线程上这样做 this.listBox1.Items.Add

标签: c# winforms tcplistener


【解决方案1】:

您的代码不完整,因此答案不完整:)

为了正确处理 UI,我已经重构了您的代码:从不同线程与 UI 交互是被禁止的操作。 这样做,行为在设计上是不确定的,因此其他一切都可能是结果。

当你必须访问 UI 时,你必须询问控件(或表单)直接访问它是否安全:InvokeRequired == false 时是安全的。

这是您重构的摘录:它适用于多个后续(非当代)连接。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp3
{
    public partial class Form1 : Form
    {
        private TcpListener listener;

        private delegate void StringVoidInvoker(string value);

        public Form1()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            // it is better to start your thread when the UI controls are just one step away from being created

            Thread t = new Thread(() =>
            {
                ListenTCPPort();
            });

            // this way, closing the form closes the thread. this is a bad practice, since you should be using a more reliable method to close the thread (e.g. events and waithandles)
            t.IsBackground = true;
            t.Start();

        }

        private void SafeLog(string value)
        {
            if (this.InvokeRequired)
            {
                // if we are being called between threads, we have to ask the original UI thread to perfom the task
                this.Invoke(new StringVoidInvoker(SafeLog), new object[] { value });
            }
            else
            {
                this.listBox1.Items.Add(value);
            }
        }

        public void ListenTCPPort()
        {
            string ipAddress, portNumber, mqName;
            ipAddress = ConfigurationManager.AppSettings.Get("IP").ToString().Trim();
            portNumber = ConfigurationManager.AppSettings.Get("PORT").ToString().Trim();
            mqName = ConfigurationManager.AppSettings.Get("MSMQ").ToString().Trim();
            int j;
            int port = Int32.TryParse(portNumber, out j) ? j : 0;
            IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ipAddress.ToString()), port);

            listener = new TcpListener(ep);
            listener.Start();


            SafeLog("Started listening requests at: " + ipAddress.ToString() + ":" + portNumber.ToString());

            while (true)
            {
                try
                {
                    const int bytesize = 1024 * 1024;
                    string message = null;
                    byte[] buffer = new byte[bytesize];

                    TcpClient sender = listener.AcceptTcpClient();

                    sender.GetStream().Read(buffer, 0, bytesize);


                    message = cleanMessage(buffer);

                    byte[] bytes = System.Text.Encoding.Default.GetBytes(message);

                    string data = System.Text.Encoding.Default.GetString(bytes);


                    SafeLog("Incoming : " + data.ToString());

                    string output = sendMessage(data, sender, mqName);
                    SafeLog(output);
                    sender.Close();

                }
                catch (Exception e)
                {
                    SafeLog("Exception : " + e.ToString());
                }
            }
        }

        private string sendMessage(string data, TcpClient sender, string mqName)
        {
            // place here your logic
            return "NOTIMPL";
        }

        private string cleanMessage(byte[] buffer)
        {
            // place here your logic
            return "NOTIMPL";
        }
    }
}

查看上面代码中的 cmets。

罪魁祸首是以正确的方式访问 UI:

    private void SafeLog(string value)
    {
        if (this.InvokeRequired)
        {
            // if we are being called between threads, we have to ask the original UI thread to perfom the task
            this.Invoke(new StringVoidInvoker(SafeLog), new object[] { value });
        }
        else
        {
            this.listBox1.Items.Add(value);
        }
    }

【讨论】:

    【解决方案2】:
    sender.GetStream().Read
    

    实际上阻塞了该方法,它一直等到有传入数据,所以你的代码一次只能处理一个连接。您应该将读取的代码放在另一个线程中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-24
      • 1970-01-01
      相关资源
      最近更新 更多