TCP侦听器在一段时间后停止侦听

时间:2019-06-05 05:59:43

标签: c# winforms tcplistener

我目前正在使用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) { }
                }
            }
        }
    }
}

2 个答案:

答案 0 :(得分:0)

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

我已经重构了您的代码,以便正确处理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";
        }
    }
}

请参阅上面代码中的注释。

罪魁祸首以正确的方式访问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);
        }
    }

答案 1 :(得分:0)

sender.GetStream().Read

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