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#]一个简易的、轻量级的方法并行执行线程辅助类
一个简易的.轻量级的方法并行执行线程辅助类 在实际应用中,经常要让多个方法并行执行以节约运行时间,线程就是必不可少的了,而多线程的管理经常又是一件头疼的事情,比如方法并行执行异步的返回问题,方法并 ...
随机推荐
- CRM BP函数
REPORT ZCRM_BP_TEST. """""""""""""& ...
- vue element-ui tree 根节点固定子节点懒加载 首次加载根节点并展开
关键代码: <el-tree ref="foldTree" node-key="id" :highlight-current="true&quo ...
- mysql新加用户设置权限
1.开通操作权限和表权限 GRANT CREATE,ALTER,DROP,INSERT,UPDATE,DELETE,SELECT ON interface.* TO test1@'%' identif ...
- H3C 什么是漫游
- Linux Swap故障之 swapoff failed: Cannot allocate memory
目录swap分区关闭方法1:释放内存缓存方法2:允许内存overcommit swap分区关闭准备调整Linux下的swap分区的使用率.在Linux下执行 swapoff -a -v报如下错误:sw ...
- 5.Lvs+Keepalived健康检查
1. Nginx+keepalived对后端服务器心跳检查(需要自定义脚本) 原理:Keepalived并不跟nginx耦合,它俩完全不是一家人但是keepalived提供一个机制:让用户自定义一个s ...
- Locust性能测试6-命令行参数详解
前言 当我们在linux上使用locust工具压测的时候,会使用no-web模式,然后需要收集运行的日志,方便查找问题. 命令行参数 输入locust --help 查看所有的命令行参数 > l ...
- C#多线程编程中的锁系统
C#多线程编程中的锁系统(二) 上章主要讲排他锁的直接使用方式.但实际当中全部都用锁又太浪费了,或者排他锁粒度太大了. 这一次我们说说升级锁和原子操作. 目录 1:volatile 2: Inter ...
- HDFS的Shell、java操作
HDFS的Shell操作 1.基本语法 bin/hadoop fs 具体命令 OR bin/hdfs dfs 具体命令 dfs是fs的实现类. 2.命令大全 [Tesla@hadoop102 h ...
- sleep、yield、wait、join的区别(阿里)
只有runnable到running时才会占用cpu时间片,其他都会出让cpu时间片.线程的资源有不少,但应该包含CPU资源和锁资源这两类.sleep(long mills):让出CPU资源,但是不会 ...