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+"\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也会相应的结束。
否则就会造成如下的情况,关闭了程序,但是任务管理器中,仍然能够看到进程。
————————————————
版权声明:本文为CSDN博主「nuistchn」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/nuistchn/article/details/50809158
C#-关于TcpListener的AcceptTcpClient()方法造成线程阻塞,进而程序无法彻底关闭的问题的更多相关文章
- Java线程阻塞方法sleep()和wait()精炼详解
版权声明:因为个人水平有限,文章中可能会出现错误,如果你觉得有描述不当.代码错误等内容或者有更好的实现方式,欢迎在评论区告诉我,即刻回复!最后,欢迎关注博主!谢谢 https://blog.csdn. ...
- 零基础学习java------day18------properties集合,多线程(线程和进程,多线程的实现,线程中的方法,线程的声明周期,线程安全问题,wait/notify.notifyAll,死锁,线程池),
1.Properties集合 1.1 概述: Properties类表示了一个持久的属性集.Properties可保存在流中或从流中加载.属性列表中每个键及其对应值都是一个字符串 一个属性列表可包含另 ...
- 多线程之Java线程阻塞与唤醒
线程的阻塞和唤醒在多线程并发过程中是一个关键点,当线程数量达到很大的数量级时,并发可能带来很多隐蔽的问题.如何正确暂停一个线程,暂停后又如何在一个要求的时间点恢复,这些都需要仔细考虑的细节.在Java ...
- java线程阻塞(sleep,suspend,resume,yield,wait,notify)
为了解决对共享存储区的访问冲突,Java 引入了同步机制,现在让我们来考察多个线程对共享资源的访问,显然同步机制已经不够了,因为在任意时刻所要求的资源不一定已经准备好了被访问,反过来,同一时刻准备好了 ...
- 让面试官心服口服:Thread.sleep、synchronized、LockSupport.park的线程阻塞有何区别?
前言 在日常编码的过程中,我们经常会使用Thread.sleep.LockSupport.park()主动阻塞线程,或者使用synchronized和Object.wait来阻塞线程保证并发安全.此时 ...
- 在Java如何保证方法是线程安全的
废话开篇 都说Java程序好些,但是我觉得Java编程这东西,没个十年八年的真不敢说自己精通Java编程,由于工作原因,开始转战Java多线程,以前没怎么接触过,所以想留点脚印在这两条路上. 切入正题 ...
- [改善Java代码]不使用stop方法停止线程
线程启动完毕后,在运行可能需要终止,Java提供的终止方法只有一个stop,但是不建议使用此方法,因为它有以下三个问题: (1)stop方法是过时的 从Java编码规则来说,已经过时的方式不建议采用. ...
- spring项目中service方法开启线程处理业务的事务问题
1.前段时间在维护项目的时候碰到一个问题,具体业务就是更新已有角色的资源,数据库已更新,但是权限控制不起效果,还是保留原来的权限. 2.排查发现原有的代码在一个service方法里有进行资源权限表的更 ...
- [C#]一个简易的、轻量级的方法并行执行线程辅助类
一个简易的.轻量级的方法并行执行线程辅助类 在实际应用中,经常要让多个方法并行执行以节约运行时间,线程就是必不可少的了,而多线程的管理经常又是一件头疼的事情,比如方法并行执行异步的返回问题,方法并 ...
随机推荐
- 汽车制造商表态:必须依靠MES系统来管控流程
汽车行业特点 汽车工业是一个高投入,高产出,集群式发展的产业部门. 汽车自身的投资,生产,研发,供应,销售,维修:前序的原材料,零部件,技术装备,物流:后序的油料,服务,信贷,咨询,保险,直至基础设施 ...
- 创建简易的SpringBoot项目
创建简易的SpringBoot项目 这两天在学习springboot,菜鸟刚刚知道这个东西,看着springboot项目下那一大堆目录都不知道从何下手,还是静下心来从最简单的创建一个项目入手,这路和大 ...
- python 使用Anaconda管理项目环境
Pycharm没有内置的python解释器,需要我们自己下载python解释器. 在很多python项目中,会导入第三方的模块,逐个去下载导入很不方便. 我们通常使用Anaconda来管理python ...
- sparkContext的初始化过程
SparkContext 初始化的过程主要的核心:1) 依据 SparkContext 的构造方法中的参数 SparkConf 创建一个SparkEnv2) 初始化,Spark UI,以便 Spark ...
- Linux装B命令
原文:https://mp.weixin.qq.com/s/CNmMRjl0iZ8EBPq5VgJHsA 1.空心字体 yum install -y figlet figlet happy 1.0 2 ...
- Java httpclent请求httpclentUtils工具类
第一种写法: import java.io.IOException; import java.io.InterruptedIOException; import java.io.Unsupported ...
- 详解Linux操作系统的iptables原理及配置
linux网络防火墙 netfilter :内核中的框架,过滤框架,网络过滤器! iptables :实现数据过滤.net.mangle等规则生成的工具 防火墙:硬件.软件.规则(匹配规则.处理办法 ...
- Tensorflow中保存模型时生成的各种文件区别和作用
假如我们得到了如下的checkpoints, 上面的文件主要可以分成三类:一种是在保存模型时生成的文件,一种是我们在使用tensorboard时生成的文件,还有一种就是plugins这个文件夹,这个是 ...
- dart 中的 try on catch
catch 捕获异常 捕获了一个异常后,就停止了捕获异常过程.捕获一个异常,你就有机会去处理它: try { breedMoreLlamas(); } on OutOfLlamasException ...
- 关于Certificate、Provisioning Profile
Certificate(证书)就是app在打包的时候必须签名,苹果iOS系统在安装app之前会验证Certificate,否则不会通过安装. Provisioning Profile简单来说就是包含A ...