我尝试在 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

本文以上的测试代码放在githubgitee 欢迎访问

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 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 判断管道是否存在将让下次连接失败的更多相关文章

  1. C# File.Exists 判断系统文件,警惕32位和64位的差异

    今天在调试一个Winform程序,使用File.Exists 判断一个已经存在的驱动文件,程序一直返回false.因为驱动文件属于系统目录,心想难道是权限不够导致的?然后用管理员身份运行软件,依然返回 ...

  2. 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 ...

  3. C# 文件存在,但是File.Exists 判断不存在的问题

    这里说的不是文件路径错了的情况,而是明明文件就存在,但是File.Exists返回false. win10系统. 查看接口说明才知道,如果你不是按管理员方式启动VS,而此文件需要管理员权限才能访问,此 ...

  4. C#中当程序的访问权限不足时,Directory.Exists和File.Exists方法不会抛出异常报错

    有些时候,我们开发的C#应用程序的执行账号,可能没有对一些文件夹和文件的访问权限,当我们使用Directory.Exists和File.Exists方法去判断这些文件夹和文件是否存在的时候,Direc ...

  5. 谨慎使用 FileInfo.Exists 实例方法,而是使用 File.Exists 静态方法替代

    如果你在代码中使用了 FileInfo.Exists 实例方法来判断一个文件是否存在,也许会发现此方法可能错误地判断来一个文件是否真的存在.这是一个坑. 本文将介绍坑的原因,并提供填坑的办法. 本文内 ...

  6. C# IO流 File.Exists,Directory.Exists, File.Create,Directory.CreateDirectory

    void Start() { CreateDirectory(); CreateFile(); } //平台的路径(封装起来的一个属性,这不是一个方法) public string path { ge ...

  7. File类 判断功能和获取功能

    package cn.zmh.File; import java.io.File; /* * * File判断功能 * * */ public class FileDemo3判断功能 { public ...

  8. 关于 System.IO.File.Exists 需要注意的事项

    各位:   .NET Framework 本省在设计的时候,他对于异常没有完全做到抛出,这样可能会有很多意想不到的问题.   比如 你在asp.net 应用程序中判断文件是否存在,这个文件可能是一个共 ...

  9. File类获取功能的方法和File类判断功能的方法

    File类获取功能的方法-public String getAbsolutePath() :返回此file的绝对路径名字符串 -public String getPath() :将此File转换为路径 ...

  10. File类获取功能的方法-File类判断功能的方法

    File类获取功能的方法 获取功能的方法 public string getAbsolutePath()∶返回此File的绝对路径名字符串. public string getPath() ︰将此Fi ...

随机推荐

  1. Solon Web 文件上传的最佳实践

    文件上传是 Web 开发中最常见的一个应用场景.一般在处理数据时,会有两种常见的方案:直接把文件流放在内存里,或者把文件流先缓冲到磁盘. 1.如果是高频且文件极小 使用纯内存模式,默认即可.如果高频小 ...

  2. IValueConverter的基础用法

    1.我们在做工控项目的时候通常设置配方的上下限 这个时候要求OK数在上下限范围之内,否则NG 首先我们绑定一个简单的List用来展示数据,我这里用学生Age来展示 <ListView Items ...

  3. QT之串口通信和多线程处理

    前言 使用QT的多线程编程,完成串口通信助手的设计. 实施 Qt5下的串口编程 使用QT5.12中自带的QSerialPort和QSerialPortInf的类实现对串口硬件的访问,通过对类的方法进行 ...

  4. getElementsByName和getElementById的区别

    1 清洗表名: <input type="text" name="fileName"/><br/> 1 var fileName = d ...

  5. 8 CSS文本属性

    8 文本属性 font-style(字体样式风格) /* 属性值: normal:设置字体样式为正体.默认值. italic:设置字体样式为斜体.这是选择字体库中的斜体字. oblique:设置字体样 ...

  6. #数位dp,高精度#洛谷 2235 [HNOI2002]Kathy函数

    题目 分析 首先这个\(f\)函数其实求的是二进制下的回文数,简单证明一下 设\(n\)在二进制下的回文数为\(n'\),第一二条显然 第三条\(f(2n)=f(n)\Rightarrow \over ...

  7. unknow or unsupported command install

    错误原因: 今天使用pip下载labelimg时,出现了"unknow or unsupported command install"的错误,这是由于电脑有多个pip文件路径所导致 ...

  8. char * 、BSTR、long、wchar_t *、LPCWSTR、string、QString、CStringA类型转换

    char* 转 BSTR char* s1 = "zhangsan"; CString s2 = CString(s1); BSTR s3 = s2.AllocSysString( ...

  9. Ez_pycode_dis qsnctfwp

    Python字节码基础 下载相关文件并打开,其中为 Python 字节码. 字节码格式为 源码行号 | 指令在函数中的偏移 | 指令符号 | 指令参数 | 实际参数值 根据上述字节码格式以及文件内容开 ...

  10. Android 开发入门(2)

    0x04 简单控件 (1)文本显示 a. 添加文本 设置文本内容主要有两种方式: XML:通过属性android:text设置 在 layout 目录下新建 activity_text_view.xm ...