建立带数据库的网站,怎么建立一个网站卖东西,公众号的微网站怎么做,24小时妇科免费问医生前言上次#xff0c;我们通过《引用 Microsoft.VisualBasic 解决程序多开的问题》。虽然它非常简单#xff0c;但是仅适用于 WinForm 应用程序#xff0c;而且还需要引用不常用的Microsoft.VisualBasic类库。因此#xff0c;我们决定深挖一下#xff0c;看看具体是如何实现… 前言上次我们通过《引用 Microsoft.VisualBasic 解决程序多开的问题》。虽然它非常简单但是仅适用于 WinForm 应用程序而且还需要引用不常用的Microsoft.VisualBasic类库。因此我们决定深挖一下看看具体是如何实现的。原理通过查看WindowsFormsApplicationBase的Run方法实现代码有删减Public Sub Run(commandLine As String())If Not IsSingleInstance ThenDoApplicationModel()Else This is a Single-Instance applicationDim pipeServer As NamedPipeServerStream NothingIf TryCreatePipeServer(ApplicationInstanceID, pipeServer) Then --- This is the first instance of a single-instance application to run.Using pipeServerWaitForClientConnectionsAsync(pipeServer, AddressOf OnStartupNextInstanceMarshallingAdaptor, cancellationToken:tokenSource.Token)DoApplicationModel()End UsingElseDim awaitable SendSecondInstanceArgsAsync(ApplicationInstanceID, commandLine, cancellationToken:tokenSource.Token).ConfigureAwait(False)awaitable.GetAwaiter().GetResult()End IfEnd If Single-Instance application
End Sub可以分析出整个流程如下创建一个NamedPipeServerStream实例如果创建成功则用WaitForClientConnectionsAsync等待第 2 个应用实例进行连接如果创建失败则用SendSecondInstanceArgsAsync向第 1 个应用实例发送数据NamedPipeServerStream使用NamedPipeServerStream类可以创建命名管道。命名管道在管道服务器和一个或多个管道客户端之间提供进程间通信。命名管道可以是单向的也可以是双向的。它们支持基于消息的通信并允许多个客户端使用相同的管道名称同时连接到服务器进程。详细使用说明请参阅官方文档《使用命名管道进行网络进程间通信》[1]实现下面我们用控制台程序进行演示const string pipeName MyIO;
const PipeOptions NamedPipeOptions PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly;static async Task Main(string[] args)
{try{using (var pipeServer new NamedPipeServerStream(pipeName: pipeName,direction: PipeDirection.In,maxNumberOfServerInstances: 1,transmissionMode: PipeTransmissionMode.Byte,options: NamedPipeOptions)){WaitForClientConnectionsAsync(pipeServer,str Console.WriteLine(str));Console.WriteLine($start server {args[0]});Console.ReadKey();}}catch{await SendSecondInstanceArgsAsync(() $call from {args[0]}).ConfigureAwait(false);}
}需要注意的是WaitForClientConnectionsAsync不能加await否则后续代码不能执行。WaitForClientConnectionsAsync实现代码如下private static async Task WaitForClientConnectionsAsync(NamedPipeServerStream pipeServer, Actionstring callback)
{CancellationTokenSource cancellationTokenSource new CancellationTokenSource();while (true){await pipeServer.WaitForConnectionAsync(cancellationTokenSource.Token).ConfigureAwait(false);try{const int bufferLength 1024;var buffer new byte[bufferLength];using (var stream new MemoryStream()){while (true){var bytesRead await pipeServer.ReadAsync(buffer.AsMemory(0, bufferLength), cancellationTokenSource.Token).ConfigureAwait(false);if (bytesRead 0){break;}stream.Write(buffer, 0, bytesRead);}stream.Seek(0, SeekOrigin.Begin);callback(Encoding.UTF8.GetString(stream.ToArray()));}}finally{pipeServer.Disconnect();}}
}循环等待客户端连接读取客户端发送的数据转换成字符串调用callback处理字符串这里是str Console.WriteLine(str)断开客户端连接SendSecondInstanceArgsAsync实现代码如下private static async Task SendSecondInstanceArgsAsync(Funcstring func)
{using (var pipeClient new NamedPipeClientStream(serverName: .,pipeName: pipeName,direction: PipeDirection.Out,options: NamedPipeOptions)){CancellationTokenSource cancellationTokenSource2 new CancellationTokenSource();cancellationTokenSource2.CancelAfter(2500);await pipeClient.ConnectAsync(cancellationTokenSource2.Token).ConfigureAwait(false);await pipeClient.WriteAsync(Encoding.UTF8.GetBytes(func()), cancellationTokenSource2.Token).ConfigureAwait(false);}
}创建客户端连接本地管道服务向服务端发送func产生的数据这里是() $call from {args[0]}Demo创建多开脚本start ConsoleApp1.exe firstInstancestart ConsoleApp1.exe secondInstancestart ConsoleApp1.exe thirdInstance执行后我们发现程序只能打开一次。并且收到了其它多开应用发过来的数据结论使用NamedPipeServerStream相对互斥锁Mutex的实现要复杂。但是由于可以进行通讯因此可以做到更灵活的控制。比如应用定时启动自己的另一个实例去下载更新下载完成后通知当前应用提示用户是否更新。想了解更多内容请关注我的个人公众号”My IO“参考资料[1]《使用命名管道进行网络进程间通信》: https://docs.microsoft.com/zh-cn/dotnet/standard/io/how-to-use-named-pipes-for-network-interprocess-communication?WT.mc_idDT-MVP-38491