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#]一个简易的、轻量级的方法并行执行线程辅助类
一个简易的.轻量级的方法并行执行线程辅助类 在实际应用中,经常要让多个方法并行执行以节约运行时间,线程就是必不可少的了,而多线程的管理经常又是一件头疼的事情,比如方法并行执行异步的返回问题,方法并 ...
随机推荐
- java集合学习(1):集合框架
集合 Collection(有时候也叫container)是一个简单的对象, Java集合工具包位于Java.util包下,Java集合主要可以划分为4个部分:List列表.Set集合.Map映射.工 ...
- springboot:使用JPA-Hibernate
步骤: 在pom.xml文件中添加mysql,spring-data-jpa的依赖. <!-- 添加mysql数据库驱动依赖--> <dependency> <group ...
- Nginx学习(二)
------------恢复内容开始------------ Nginx配置文件 主配置文件结构:四部分 main block:主配置段,既全局配置段,对Http,mail都有效 event{ }事件 ...
- Python之路(第四十四篇)线程同步锁、死锁、递归锁、信号量
在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lock ...
- 响应式js库——rxjs
原文地址:https://rxjs.dev/guide/overview 简介 RxJS 是组合异步以及基于事件的使用可观察者序列的程序类库.它提供一个核心类型,Observable,附属类型(Obs ...
- Excel 批量导入Mysql(创建表-追加数据)
之前弄数据库的时候, 测试excel导mysql, 中间用pandas 处理后再入库. 直接上代码, 此种有真意, 尽在不言中. #!/usr/bin/env python # coding: ut ...
- Oracle数据库备份还原笔记
Oracle数据库备份还原笔记 通过查阅资料知道Oracle备份还原的方式有三种.分别的是导出/导入.热备份和冷备份.导出/导入是一种逻辑备份.而热备份和冷备份是物理备份.[参考资料(https:// ...
- rest framework 之视图
一.APIView APIView 直接继承 View(Django 内置的 View),也就是说 APIView 是最贴近原生 Django 的 View 的. 因此可定制程度高,根据请求方法不同执 ...
- httprunner运行报错问题:base url missed
在httprunner运行报错问题 代码书写: 当此段yml文件运行时会出现一下错误 在出现此错误时,为base_url的格式出现错误,只需修改base_url的位置 修改位置后运行yml文件 运行成 ...
- Docker容器的简单使用
1. docker的使用 1> 创建容器 创建并启动容器: docker run -it -name 容器名 镜像: 版本 /bin/sh(bash) 创建并不启动容器:docker crea ...