登山-C#-关于TcpListener的AcceptTcpClient()方法造成线程阻塞,进而程序无法彻底关闭的问题

在《C#高级编程》第7版第24章,有提到使用TCP类。

书中写了一个实例,两个winform,其中一个点击按钮发送字符串,另一个winform进行接收。这个实例有个缺点,只能接收一次。

我将这个实例进行了改造。第一版做好后,可以进行接收和发送,但是出现一个问题,就是在关闭程序后,在电脑的任务管理器中看到还有进程在跑。

进行了一些尝试后改了第二版,终于解决了这个问题。

看一眼这个程序

登山-C#-关于TcpListener的AcceptTcpClient()方法造成线程阻塞,进而程序无法彻底关闭的问题_第1张图片

在两台电脑上分别运行此程序,注意要设置对方的IP地址。

登山-C#-关于TcpListener的AcceptTcpClient()方法造成线程阻塞,进而程序无法彻底关闭的问题_第2张图片

 

我直接贴上第二版的代码,然后在标明修改的哪儿。

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

namespace TCPSend
{
    public partial class Form1 : Form
    {
        //定义一个委托,用于更新Form1上控件。
        protected delegate void UpdateDisplayDelegate(string text);
        public Thread thread = null;
        public TcpClient tcpClientReceiver = null;
        TcpListener tcpListener = null;
        public Boolean boolStop = false;

        public Form1()
        {
            InitializeComponent();
            thread = new Thread(new ThreadStart(Listen));
            thread.Start();
        }

        public void Listen()
        {
            string LocalIp = GetSelfIp();
            if (LocalIp == null)
            {
                return;
            }
            IPAddress localAddr = IPAddress.Parse(LocalIp);
            Int32 port = 2112;
            tcpListener = new TcpListener(localAddr, port);
            tcpClientReceiver = new TcpClient();
            tcpListener.Start();
            while (true)
            {
                if (!tcpListener.Pending()) 
                {
                    //为了避免每次都被tcpListener.AcceptTcpClient()阻塞线程,添加了此判断,
                    //no connection requests have arrived。
                    //当没有连接请求时,什么也不做,有了请求再执行到tcpListener.AcceptTcpClient()
                }
                else
                {
                   tcpClientReceiver = tcpListener.AcceptTcpClient();
                   NetworkStream ns = tcpClientReceiver.GetStream();
                   StreamReader sr = new StreamReader(ns);
                   string result = sr.ReadToEnd();     
                   Invoke(new UpdateDisplayDelegate(UpdateDisplay), new object[] { result });
                }
                if (boolStop)
                {
                    break;
                }
            }
 
        }

        public void UpdateDisplay(string text)
        {
            string currentContents = textBox4.Text;
            currentContents += text+"\r\n";   //必须用"\r\n"在窗口中才能体现出换行
            textBox4.Text = currentContents;
        }

        //send message
        private void button1_Click(object sender, EventArgs e)
        {
            SendMessage();
        }

        public void SendMessage()
        {
            TcpClient tcpClient = new TcpClient(textBox1.Text, Int32.Parse(textBox2.Text));
            NetworkStream ns = tcpClient.GetStream();
            string message = textBox3.Text;
            byte[] contentBytes = Encoding.GetEncoding("utf-8").GetBytes(message); //将string类型转换为byte[]
            for (int i = 0; i < contentBytes.Length; i++)
            {
                ns.WriteByte(contentBytes[i]);
            }
            ns.Close();
            tcpClient.Close();
            textBox3.Text = "";
        }

        //获得本地的IP地址
        public string GetSelfIp()
        {
            System.Net.IPAddress[] addressList = Dns.GetHostByName(Dns.GetHostName()).AddressList;
            if (addressList.Length == 1)
            {
                return addressList[0].ToString(); 
            }
            else
            {
                MessageBox.Show("当前只支持设置一个IP的电脑,您的电脑设有多个IP地址");
            }
            return null;
        }


        //在关闭之前,将boolStop设置为true,thread既可以结束了。
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            boolStop = true;
        }
    }
}


相对于第一版,主要是添加了变量boolStop,用于控制线程中while循环结束的时机。第二点就是在while循环中增加了一个判断,if (!tcpListener.Pending()),这样在对方没有发送消息时,是不会执行到tcpListener.AcceptTcpClient();的。这样就不会造成线程的阻塞了。这样直接关闭了winform,线程thread也会相应的结束。

否则就会造成如下的情况,关闭了程序,但是任务管理器中,仍然能够看到进程。

登山-C#-关于TcpListener的AcceptTcpClient()方法造成线程阻塞,进而程序无法彻底关闭的问题_第3张图片

 

这个程序还有很多地方可以改进,后续再写。

 

 

你可能感兴趣的:(C#)