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


    https://blog.csdn.net/nuistchn/article/details/50809158

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

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

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

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

    看一眼这个程序

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

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

    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+" "; //必须用" "在窗口中才能体现出换行
    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也会相应的结束。

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

     
    ————————————————
    版权声明:本文为CSDN博主「nuistchn」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/nuistchn/article/details/50809158

  • 相关阅读:
    Kubernetes 命令行工具之kubctl
    新一代数据库之Etcd 简介
    算法题 打家劫舍(动态规划)
    算法题 位1的个数
    Class强制类型转换
    算法题 阶乘后的零
    算法题 Excel表列序号
    多数元素
    有序数组两数之和
    一杯果汁和一杯水的故事
  • 原文地址:https://www.cnblogs.com/zkwarrior/p/11738654.html
Copyright © 2020-2023  润新知