dotnet 6 使用 File.Exists 判断管道是否存在将让下次连接失败
我尝试在 dotnet 6 使用 File.Exists 判断管道是否存在,如果管道存在再进行连接。然而这个逻辑将会接下来的 NamedPipeClientStream 调用 Connect 连接失败
这个问题似乎是 CLR 底层的问题,我将问题报告给官方,请看 Using File.Exists to check the pipe created will make the NamedPipeClientStream connect fail · Issue #69604 · dotnet/runtime
使用 File.Exists 判断管道是否存在的代码如下
File.Exists(@"\\.\pipe\" + PipeName);
然而以上代码将会在 dotnet 6 下让 NamedPipeClientStream 调用 Connect 连接失败。这个逻辑如果放在 .NET Framework 下运行,是能成功的
最简复现步骤如下,先使用 NamedPipeServerStream 启动管道服务
void StartServer()
{
var server = new NamedPipeServerStream(PipeName,
PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, 1024, 1024);
server.BeginWaitForConnection(OnWaitForConnection, server);
}
接下来使用 File.Exists 判断管道是否存在
File.Exists(@"\\.\pipe\" + PipeName);
再使用 NamedPipeClientStream 进行连接
void StartClient()
{
var localServer = ".";
var pipeDirection = PipeDirection.InOut;
var client = new NamedPipeClientStream(localServer,
PipeName, pipeDirection, PipeOptions.Asynchronous);
var timeout = 1000 * 5;
client.Connect(timeout);
}
运行代码,可以看到 Connect 方法抛出 TimeoutException 错误
核心原因是在 .NET 6 通过 GetFileAttributesW 去判断管道是否存在,然而根据堆栈网 的描述,通过 GetFileAttributesW 去判断一个非文件系统的对象,会有非预期的行为。这也就是管道连接失败的原因。那为什么 .NET Framework 没问题?因为 .NET Framework 是先调用 FindFirstFile 进行判断
因此一个解决方法是采用和 .NET Framework 一样的 FindFirstFile 方法进行判断管道是否存在,代码如下
private static bool IsPipeExists(string pipeName)
{
try
{
// 不要用 File.Exists 判断,内部会调用 GetFileAttributes 导致管道无法被连接
unsafe
{
// 这里是一个结构体,但是不关心内容,直接栈上分配点空间给它
var findFileData = stackalloc byte[604];
var file = FindFirstFile(@"\\.\pipe\" + pipeName, (IntPtr)findFileData);
const nint INVALID_HANDLE_VALUE = -1;
if (file != INVALID_HANDLE_VALUE)
{
FindClose(file);
return true;
}
}
}
catch
{
}
return false;
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "FindFirstFileW", ExactSpelling = true)]
private static extern SafeFileHandle FindFirstFile([In] string lpFileName, [In] IntPtr lpFindFileData);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "FindClose", ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FindClose([In] IntPtr hFindFile);
如果不想碰不安全代码,也可以采用判断文件夹里面的文件是否存在的方法判断管道是否存在
Directory.EnumerateFiles(@"\\.\pipe\", PipeName).Any();
只是文件夹的判断方法会比使用 FindFirstFile 的速度慢一点点,我测试大概是 3-5 毫秒左右
更多请看 Detecting that NamedPipe exists - Andrii Snihyr
本文以上的测试代码放在github 和 gitee 欢迎访问
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin e26bdd0bced93db8edf8be18f1062e571f3d1861
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
获取代码之后,进入 HallwhallkernarbafejaNakeldibi 文件夹
dotnet 6 使用 File.Exists 判断管道是否存在将让下次连接失败的更多相关文章
- C# File.Exists 判断系统文件,警惕32位和64位的差异
今天在调试一个Winform程序,使用File.Exists 判断一个已经存在的驱动文件,程序一直返回false.因为驱动文件属于系统目录,心想难道是权限不够导致的?然后用管理员身份运行软件,依然返回 ...
- File.Exists 判断不了虚拟路径
https://www.shuzhiduo.com/topic/file-exists-%E5%88%A4%E6%96%AD%E4%B8%8D%E4%BA%86%E8%99%9A%E6%8B%9F%E ...
- C# 文件存在,但是File.Exists 判断不存在的问题
这里说的不是文件路径错了的情况,而是明明文件就存在,但是File.Exists返回false. win10系统. 查看接口说明才知道,如果你不是按管理员方式启动VS,而此文件需要管理员权限才能访问,此 ...
- C#中当程序的访问权限不足时,Directory.Exists和File.Exists方法不会抛出异常报错
有些时候,我们开发的C#应用程序的执行账号,可能没有对一些文件夹和文件的访问权限,当我们使用Directory.Exists和File.Exists方法去判断这些文件夹和文件是否存在的时候,Direc ...
- 谨慎使用 FileInfo.Exists 实例方法,而是使用 File.Exists 静态方法替代
如果你在代码中使用了 FileInfo.Exists 实例方法来判断一个文件是否存在,也许会发现此方法可能错误地判断来一个文件是否真的存在.这是一个坑. 本文将介绍坑的原因,并提供填坑的办法. 本文内 ...
- C# IO流 File.Exists,Directory.Exists, File.Create,Directory.CreateDirectory
void Start() { CreateDirectory(); CreateFile(); } //平台的路径(封装起来的一个属性,这不是一个方法) public string path { ge ...
- File类 判断功能和获取功能
package cn.zmh.File; import java.io.File; /* * * File判断功能 * * */ public class FileDemo3判断功能 { public ...
- 关于 System.IO.File.Exists 需要注意的事项
各位: .NET Framework 本省在设计的时候,他对于异常没有完全做到抛出,这样可能会有很多意想不到的问题. 比如 你在asp.net 应用程序中判断文件是否存在,这个文件可能是一个共 ...
- File类获取功能的方法和File类判断功能的方法
File类获取功能的方法-public String getAbsolutePath() :返回此file的绝对路径名字符串 -public String getPath() :将此File转换为路径 ...
- File类获取功能的方法-File类判断功能的方法
File类获取功能的方法 获取功能的方法 public string getAbsolutePath()∶返回此File的绝对路径名字符串. public string getPath() ︰将此Fi ...
随机推荐
- 记录--详解 XSS(跨站脚本攻击)
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言:我们知道同源策略可以隔离各个站点之间的 DOM 交互.页面数据和网络通信,虽然严格的同源策略会带来更多的安全,但是也束缚了 Web. ...
- QT 智能指针 QPointer QScopedPointer QSharedPointer QWeakPointer QSharedDataPointer 隐式共享 显示共享
QPointer QPointer 使一种受保护的指针,当其引用的对象被销毁时,它会被自动清除(但是,销毁引用对象还是必须手动delete).QPointer所指向的对象必须是QObject或其派生类 ...
- ElasticSearch8 - SpringBoot整合ElasticSearch
前言 springboot 整合 ES 有两种方案,ES 官方提供的 Elasticsearch Java API Client 和 spring 提供的 [Spring Data Elasticse ...
- Oracle 隐式数据类型转换
Oracle类型转换规则: 对于insert和update操作,oracle将值转换为受影响的的列的类型. 对于select操作,oracle会将列的值的类型转换为目标变量的类型. 看如下实验: 1. ...
- ‘MsBuild.exe‘ 不是内部或外部命令,也不是可运行的程序
方法一: 在系统环境变量中的path变量中添加一条路径: 32位环境 C:\Windows\Microsoft.NET\Framework\v4.0.30319 64位环境 C:\Windo ...
- KingbaseES V8R6 中walminer的使用
前言 walminer工具可以帮助dba挖掘wal日志中的内容,看到某时间对应数据库中的具体操作.例如挖掘日志后可以看到数据库某时间有哪些dml语句. walminer的限制与约束 WalMiner工 ...
- Modbus报文详解
Modbus是一种串行通信协议,最初由Modicon公司(现为施耐德电气的一部分)在1979年为使用其PLC(可编程逻辑控制器)而开发.Modbus已成为工业领域内广泛使用的一种通信协议,特别是对于监 ...
- Vue入门笔记三(Vuex)
<Vue.js项目实战> Vuex 集中式的状态管理 Vuex从Flux(由Facebook开发)的概念中获取得灵感.Flux又一系列指导原则构成,阐明了如何使用集中式store来实现组件 ...
- MyBatis的映射关系
MyBatis的映射关系是有一个默认的,采用下划线命名的方式将数据库表的列名按照驼峰式映射成 Java 实体类的属性名 举个例子数据库表名为 tb_user,其中的字段名为 inst_code,对应的 ...
- MybatisPlus的那些坑
1.实体类属性会被错误解析,需要加上注解@TableField @TableField("front_of_id_card") //身份证正面 private String fro ...