记录一次WPF程序进程挂起问题
## 1. 使用背景
开发`WPF`单进程项目,在项目中使用`MongoDB`数据库,需要连接多个不同的数据库实例,另外项目框架采用了事件聚合器来管理模块间的通知调用,基于`NetMQ`实现了一个`ZeroMQPublisher`和`ZeroMQSubscriber`。
**事件聚合器服务实现方案**:
* `ZeroMQPublisher` 启动时会监听本机地址的一个端口(比如`tcp://*:5866`)
* `ZeroMQSubscriber`启动时需要去连接NetMQ服务端(比如:`tcp://127.0.0.1:5866`)
**启动数据库实例的实现方案**:
在`C#`代码中通过`Process`来启动`mongod.exe`,启动时分别指定不同的启动参数(`--dbpath` `--port` `--replSet` `--logpath` 等等)。该逻辑在应用程序启动时调用。
* 具体实现代码片段如下:
<!---->
var startInfo = new ProcessStartInfo
{
FileName = processName,
Arguments = $"--dbpath \"{mongoConfig.DBPath}\" --port {mongoConfig.Port} --replSet {mongoConfig.ReplicaSetName} " +
$"--logpath {Path.Combine(mongoConfig.DBPath, "mongod.log")} --logappend",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
// 指定用于读取标准输出流的编码。指定为 UTF8 可以确保正确读取输出
StandardOutputEncoding = Encoding.UTF8,
// 指定用于读取标准错误流的编码。同样,指定为 UTF8 可以确保正确读取错误输出
StandardErrorEncoding = Encoding.UTF8
};
var _mongoProcess = new Process { StartInfo = startInfo };
_mongoProcess.Start();
// 订阅输出和错误事件
_mongoProcess.OutputDataReceived += (sender, e) =>
{
if (!string.IsNullOrEmpty(e.Data))
{
outputMsgCallback?.Invoke("MongoDB 输出: " + e.Data);
}
};
_mongoProcess.ErrorDataReceived += (sender, e) =>
{
if (!string.IsNullOrEmpty(e.Data))
{
outputMsgCallback?.Invoke("MongoDB 错误: " + e.Data);
}
};
_mongoProcess.BeginOutputReadLine();
_mongoProcess.BeginErrorReadLine();
注:为了实现数据库实例在`WPF`程序退出后依然可以连接,故在退出程序时,未清除上面的`Process`资源。
* 实现效果:
* a. 可以通过配置启动多个不同的`mongo db` 数据库实例;
* b. 可以将`mongo db`数据库实例启动的日志重定向输出,并通过`outputMsgCallback`的定义来记录起来(已有指定的 --logpath ,其实可以不需要重定向的输出信息)
## 2. 问题现象
* `WPF`程序退出后,再次启动程序,会提示如下报错信息:
<!---->
内部异常:
SocketException: 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。
* 检查端口占用情况,执行 `netstat -ano | finstr :5866`,返回如下信息:
<!---->
TCP 0.0.0.0:5866 0.0.0.0:0 LISTENING 46064
TCP 127.0.0.1:3172 127.0.0.1:5866 ESTABLISHED 46064
TCP 127.0.0.1:5866 127.0.0.1:3172 ESTABLISHED 46064
通过上面显示的进程`id 46064` 去查询对应的进程(`tasklist /FI "PID eq 46064" `),显示查询不到对应的进程信息。

## 3. 问题原因及分析
1. 检查实现逻辑,发现在应用程序退出时,已调用对应的`NetMQ`的`Dispose`释放逻辑;
2. 优化尝试:在释放连接资源前,先执行`DiscConnect`逻辑亦无法解决问题;
3. 工具分析 `[TCPView](https://learn.microsoft.com/en-us/sysinternals/downloads/tcpview?spm=5aebb161.543df828.0.0.737f7038lsFU2W)`
使用`TCPView`工具可以看到上面对应的3个`tcp`的连接信息,但是无法查看到关联的实际进程信息,依然无法解决问题。
4\. 使用`[ProcessExplorer](https://learn.microsoft.com/en-us/sysinternals/downloads/process-explorer)`工具查看进程信息,选择`mongod.exe`,查看属性,发现其会显示`Parent`为上面的WPF应用进程。


`kill`这两个`mongod.exe`后,不再出现上面的端口占用问题。因此,问题的主要原因是`mongod.exe`启动的数据库实例进程和主进程是关联在一起的,根本原因是`Process`启动进程是未和主进程相隔离。
## 4. 解决方案
1. 修改进程启动方式:
<!---->
var startInfo = new ProcessStartInfo
{
FileName = processName,
Arguments = $"--dbpath \"{mongoConfig.DBPath}\" --port {mongoConfig.Port} --replSet {mongoConfig.ReplicaSetName} " +
$"--logpath {Path.Combine(mongoConfig.DBPath, "mongod.log")} --logappend",
UseShellExecute = true,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
};
* 通过`Shell`来启动进程(`UseShellExecute = true`),而不是直接由当前应用程序启动;
* 隐藏启动的`Shell`窗口(`WindowStyle = ProcessWindowStyle.Hidden`);
记录一次WPF程序进程挂起问题的更多相关文章
- c# 守护进程,WPF程序自守护
原文:c# 守护进程,WPF程序自守护 版权声明:本文为博主原创文章,转载请注明出处. https://blog.csdn.net/lwwl12/article/details/79035246 如何 ...
- WPF 程序如何跨窗口/跨进程设置控件焦点
原文:WPF 程序如何跨窗口/跨进程设置控件焦点 WPF 程序提供了 Focus 方法和 TraversalRequest 来在 WPF 焦点范围内转移焦点.但如果 WPF 窗口中嵌入了其他框架的 U ...
- WPF 程序如何移动焦点到其他控件
原文:WPF 程序如何移动焦点到其他控件 WPF 中可以使用 UIElement.Focus() 将焦点设置到某个特定的控件,也可以使用 TraversalRequest 仅仅移动焦点.本文介绍如何在 ...
- Linux C 程序 进程控制(17)
进程控制 1.进程概述现代操作系统的特点在于程序的并行执行.Linux是一个多用户多任务的操作系统.ps .pstree 查看进程进程除了进程id外还有一些其他标识信息,可以通过相应的函数获得.// ...
- WPF 程序中启动和关闭外部.exe程序
当需要在WPF程序启动时,启动另一外部程序(.exe程序)时,可以按照下面的例子来: C#后台代码如下: using System; using System.Collections.Generic; ...
- [Python 学习]2.5版yield之学习心得 - limodou的学习记录 - limodou是一个程序员,他关心的焦点是Python, DocBook, Open Source …
[Python 学习]2.5版yield之学习心得 - limodou的学习记录 - limodou是一个程序员,他关心的焦点是Python, DocBook, Open Source - [Pyth ...
- Winform 程序嵌入WPF程序 并发送消息
废话不多说,先看解决方案目录 WindowsFormsDemo是主程序,WpfApp是嵌入的WPF程序,先看WPF程序,程序默认启动的页面是MainWindow.xaml,这里注释掉App.xaml里 ...
- WPF 一个空的 WPF 程序有多少个窗口
原文:WPF 一个空的 WPF 程序有多少个窗口 好多小伙伴说 WPF 的程序有五个窗口,但是我尝试使用了 EnumThreadWindows 去获取的时候居然拿到了 10 多个窗口 在 WPF 内部 ...
- 进程 PCB 进程挂起
7-1 进程定义 OS系统从只能跑一个程序到能跑多个.进程可以描述程序的执行过程. 进程:一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程. 只有当一个程序被OS加载到内存中,cpu对其 ...
- 在WPF程序中打开网页:使用代理服务器并可进行JS交互
本项目环境:使用VS2010(C#)编写的WPF程序,通过CefSharp在程序的窗体中打开网页.需要能够实现网页后台JS代码中调用的方法,从网页接收数据,并能返回数据给网页.运行程序的电脑不允许上网 ...
随机推荐
- Java日志手机号脱敏工具类
背景 在开发过程中,很容易将用户敏感信息,例如手机号码.身份证等,打印在日志平台.为了保护用户数据,又不影响日志的打印,需要将日志中的敏感信息进行脱敏. 效果 没看明白,强烈建议 pull项目,执行一 ...
- Echarts 提示组件
1.开启指示器 默认情况下,指示器是关闭状态,如果需要开启,直接配置tooltip字段即可 var option = { tooltip:{}, } 2.指示器的触发类型 触发类型的字段为trigge ...
- uni-app 横竖屏问题
前情 uni-app是我很喜欢的跨平台框架,它能开发小程序,H5,APP(安卓/iOS),对前端开发很友好,自带的IDE让开发体验也很棒,公司项目就是主推uni-app 坑位 最近有用户反馈闪屏页也叫 ...
- ruoyi若依前端验证码不显示的终极解决方法-20230721
搞了3天啊,查了各种资料啊. 然后使劲的看log啊,总算搞定了啊. 一般情况,本地开发环境测试没问题,部署到服务器就各种不适应,就是服务器配置的问题了. 本次这种验证码不显示,典型的nginx的配置 ...
- TypeScript 源码详细解读(2)词法1-字符处理
本节文章研究的代码位于 tsc/src/compiler/scanner.ts 字符 任何源码都是由很多字符组成的,这些字符可以是字母.数字.空格.符号.汉字等-- 每一个字符都有一个编码值,比如字符 ...
- 【Python基础练习】实验3:列表、字典、集合
实验3:列表.字典.集合 姓名:萌狼蓝天 时间:2023年11月6日 Python:3.12 博客:https://wwww.mllt.cc 实验目的 (1)了解列表.元组.字典和集合的概念 (2)学 ...
- centOS7安装nginx及nginx配置
安装所需插件1.安装gccgcc是linux下的编译器在此不多做解释,感兴趣的小伙伴可以去查一下相关资料,它可以编译 C,C++,Ada,Object C和Java等语言 命令:查看gcc版本 gcc ...
- SolidState靶机通关教程及提权
声明!本文章及工具分享仅仅只是供大家学习交流为主,如有任何触犯法律的行为,均与本人及团队无关!!! 工具链接:https://pan.quark.cn/s/33795a10039c 一.靶机搭建 点击 ...
- 基于Netty,从零开发IM(三):编码实践篇(群聊功能)
本文由作者"大白菜"分享,有较多修订和改动.注意:本系列是给IM初学者的文章,IM老油条们还望海涵,勿喷! 1.引言 接上两篇<IM系统设计篇>.<编码实践篇(单 ...
- 一个超经典 WinForm,WPF 卡死问题的终极反思
一:背景 1. 讲故事 写这篇文章起源于训练营里一位朋友最近在微信聊到他对这个问题使用了一种非常切实可行,简单粗暴的方式,并且也成功解决了公司里几个这样的卡死dump,如今在公司已是灵魂级人物,让我也 ...