关闭TCP连接和退出应用程序的方法

时间:2017-02-08 08:41:39

标签: c# sockets network-programming tcplistener

这是一个TCP程序,它从TCP连接接收数据,然后解析它并将其传输到另一个TCP连接。当我退出应用程序时,它不起作用。它将作为系统中的一个过程保留。

由于我不是一位经验丰富的开发人员,有人可以帮助我找到此代码中的错误..

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

namespace Machine_Feeder
{
    public partial class FeederControlMonitor : Form
    {
        TcpListener Listener = null;
        public string Status = string.Empty;
        public Thread T = null;
        public FeederControlMonitor()
        {
            InitializeComponent();
         }

        private void FeederControlMonitor_Load(object sender, EventArgs e)
        {
            txtStatus.Text = "Feeder waiting for data...";
            ThreadStart Ts = new ThreadStart(StartReceiving);
            T = new Thread(Ts);
            T.Start();
        }
        public void StartReceiving()
        {
            ReceiveTCP(9100);
        }
        public void ReceiveTCP(int portN)
        {

            try
            {
                Listener = new TcpListener(IPAddress.Any, portN);
                Listener.Start();

            }
            catch (Exception ex)
            {
                File.WriteAllText(@"C:\\Drive\\ex.txt", ex.Message);
                Console.WriteLine(ex.Message);
            }
       try
            {
                while (true)
                {
                    Socket client = Listener.AcceptSocket();
                    var childSocketThread = new Thread(() =>
                    {
                        byte[] data = new byte[10000];
                        int size = client.Receive(data);
                        ParseData(System.Text.Encoding.Default.GetString(data));
                        client.Close();
                    });
                    childSocketThread.Start();
                    }
                    Listener.Stop();
  }
            catch (Exception ex)
            {
                File.WriteAllText(@"C:\\Drive\\ex.txt", ex.Message);
            }
        }

        public void ParseData(string data)
        {
            var useFulData = data.Substring(data.IndexOf("F1")).Replace("  ", " ");// Space
            useFulData = useFulData.Remove(useFulData.IndexOf("<ETX>"));
            string[] delimeters = { "<DEL>", "<ESC>" };
            var listOfValues = useFulData.Split(delimeters, StringSplitOptions.None).ToList();
            int pos = 0;
            for (int i = 1; i < listOfValues.Count; i += 2, pos++)
            {
                listOfValues[pos] = listOfValues[i];
            }
            listOfValues.RemoveRange(pos, listOfValues.Count - pos);
            txtHealthCard.Invoke((Action)delegate { txtHealthCard.Text = listOfValues[0]; });
            txtCID.Invoke((Action)delegate { txtCID.Text = listOfValues[1]; });
            txtMedicalFitLocation.Invoke((Action)delegate { txtMedicalFitLocation.Text = listOfValues[2]; });
            txtGender.Invoke((Action)delegate { txtGender.Text = listOfValues[3]; });
            txtAge.Invoke((Action)delegate { txtAge.Text = listOfValues[4]; });
            txtPatientName.Invoke((Action)delegate { txtPatientName.Text = listOfValues[5]; });


            MyProtocolMaker(listOfValues[5], 
                listOfValues[4], 
                listOfValues[2], 
                listOfValues[3], 
                listOfValues[8], 
                listOfValues[1], 
                listOfValues[10], 
              );
        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            Listener.Stop();
            T.Abort();
            this.Close();
        }
        private void MyProtocolMaker(
            string patientName,
            string patientAge,
            string mfitLocation,
            string gender,
            string healthCardNo,
           )
        {
            string feederInfo = "^^^P^PI" + healthCardNo + "^PN" + patientName + "^PA" + patientAge + "^PS" + gender + "^P7" + mfitLocation +"^_SS^^^_S";
            System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient("127.0.0.1", 8001);
            NetworkStream serverStream = clientSocket.GetStream();
            byte[] outStream = System.Text.Encoding.ASCII.GetBytes(feederInfo);
            serverStream.Write(outStream, 0, outStream.Length);
            serverStream.Flush();
            serverStream.Close();
            clientSocket.Close();
         }

        private void FeederControlMonitor_FormClosing(object sender, FormClosingEventArgs e)
        {
            Listener.Stop();
            T.Abort();
            this.Close();
        }
    }
}

1 个答案:

答案 0 :(得分:1)

问题是,您是在线程中创建线程。这些线程使应用程序保持活跃。尝试将它们标记为后台线程:(这是红带解决方案)

var childSocketThread = new Thread(() =>
{
    byte[] data = new byte[10000];
    int size = client.Receive(data);  // <-- the thread hangs on these and will block termination
    ParseData(System.Text.Encoding.Default.GetString(data));
    client.Close();
});
childSocketThread.IsBackground = true;   // <---
childSocketThread.Start();

当线程标记为后台(默认)时,它们将阻止应用程序终止。您应该创建一个列表来存储客户端线程,这样您就可以很好地退出这些线程。

除非没有别的办法,否则你不应该中止一个线程。你应该退出线程中的while循环而不是中止。

好的方法是使用ManualResetEvent

字段:

private ManualResetEvent _terminating = new ManualResetEvent(false);
线程中的

while (_terminating.WaitOne(0))
{
    // thread code
}
退出时

_terminating.Set();
T.Join();

旁注:TCP正在流式传输,所以只读取10k字节的数据,并不能保证完整的数据包。