目录

介绍

DotNet 远程处理框架

约束、限制

客户端——服务器定义

接口

服务器通知参数

服务器异常

服务器实现

客户端实现

如何测试示例

本文中的项目

结论


  • 下载演示 - 194 KB
  • 下载源码 - 114.5 KB

介绍

在我担任计算机数字控制 (CNC) 高级软件工程师期间,我有机会开发一个涵盖广泛应用的框架。本文专门介绍了具有服务器回调通知的通用客户端——服务器通信框架。

后续文章将重点介绍使用log4net和DbgView进行诊断、常见的面向WinForm的框架以及用于查看日志文件和实现框架的LogViewer应用程序作为示例。

简单就是美,我已经从框架中删除了本文不需要的所有内容。

本文仅描述在客户端——服务器通信中实现通用远程处理框架必须了解的内容。类的详细情况汇报给每个人欣赏。

DotNet 远程处理框架

在Client-Server通信中,对于客户端来说重要的是它能够随时连接到服务器,无论是在客户端之前或之后启动服务器还是由于某种原因中断了通信并稍后重新建立。对于服务器来说,重要的是它能够识别客户端是否连接,是否断开连接,或者通信由于某种原因被切断并稍后重新建立。

客户端——服务器通信中最重要的事情是服务器应该能够向客户端返回通知。

约束、限制

通用远程处理框架假定多个客户端可以连接到服务器,但服务器只有一个Sink用于所有客户端。它还假定客户端和服务器之间的连接是永久的,没有租用。

客户端——服务器定义

在实现客户端——服务器通信之前,有必要定义两件事。

  1. 服务器呈现给客户端的接口。
  2. 服务器用于通知客户端的通知参数的类型。

由于此信息由服务器和客户端使用,因此需要在客户端和服务器的公共项目中定义它们。对于本文中的测试示例,常用项目是TestLibrary。客户端项目是TestClient,服务器是TestServer.

接口

对于此测试示例,接口如下所示:

namespace TestLibrary
{/// Interface provided by the server for clients.public interface ITestInterface : IConnect<EventArgs>{/// The server will send this message back to the clients asynchronouslyvoid Execute(string message);/// The server will send this message back to the clients asynchronouslyvoid Execute(Guid clientID, string message);/// The server will send this message back to the clients synchronously.void ExecuteSync(string message);/// The server will generate an exception.void ExecuteException();/// The server will notify an exception.void ExecuteNotifyException();}
}

接口必须始终派生自IConnect<EventArgs>! IConnect<EventArgs>接口在RemoteServer类服务器端和RemoteConnector类客户端中实现。只有您的接口是使用这两个基类来实现的。

可以在此接口中定义任何方法,但必须注意所使用的方法参数必须是可序列化的。本示例定义了 fife 方法,但数量不限。这些方法只是向服务器发送消息或要求服务器生成异常。服务器实现将通过异步或同步通知将消息发送回客户端或生成异常作为示例。

服务器通知参数

服务器通知参数如下所示:

namespace TestLibrary
{[Serializable]public class TestMessageArgs : EventArgs{/// The message.public string Message { get; }/// Constructs a TestMessageArgs object.public TestMessageArgs(string message){Message = message;}}
}

它应该来自EventArgs但更重要的是它应该是可序列化的。

该服务器上的Executes(..)信息将发回消息通知到使用此参数的客户端。

服务器异常

有两种异常类型。通知异常或服务器抛出的异常。您可以在服务器上捕获服务器异常并通过NotifyExceptionArgs通知通知客户端发生了异常,或者您可以在客户端上捕获通用服务器异常。可以在公共库中定义一个异常,但该异常应该是可序列化的。

服务器实现

服务器实现如下所示:

namespace TestServer
{/// Class to manage a TestServer.public class TestServer : RemoteServer<TestSink>{/// Constructs a TestServer object, the base class has no default constructor.public TestServer(IChannel channel): base(channel) { }/// Notify all clientspublic void SendNotificationToAllClients(string message){Sink?.PerformNotifyClients(new TestMessageArgs(message));}}
}

该TestServer类从泛型的RemoteServer<T>派生,并只用于定义Sink为T参数。

应用程序无法访问由DotNet远程处理创建RemoteServer<T>的T接收器,但该类提供了一个接收器属性,该属性在且仅当第一个客户端连接时创建。一经创建,Sink即为永久。

RemoteServer<T>类提供事件:

  • ClientConnect: 客户端连接
  • ClientDisconnect: 客户端断开连接
  • Starting: 服务器正在启动
  • Waiting: 服务器正在等待,可以从事件处理程序中取消服务器
  • Stopping: 服务器正在停止
  • Stopped: 服务器已停止

最重要的服务器端代码是Sink,根据定义服务器中只有一个 Sink。它实现了服务器接口。

namespace TestServer
{/// Class to manage the Server Sink defined by its Interface.public class TestSink : NotifyClientSink, ITestInterface{/// The server will send the message back to the clients asynchronously.public void Execute(string message){PerformNotifyClients(new TestMessageArgs(message));}/// The server will send the message back to the client asynchronously.public void Execute(Guid clientID, string message){PerformNotifyClient(clientID, new TestMessageArgs(message));}/// The server will send the message back to the clients synchronously.public void ExecuteSync(string message){PerformNotifyClientsSync(new TestMessageArgs(message));}/// The server will generate an exception.public void ExecuteException(){throw new NotImplementedException("ExecuteException");}/// The server will notify an exception.public void ExecuteNotifyException(){try{// server code that generates an exceptionthrow new ApplicationException("ExecuteNotifyException");}catch (Exception ex){PerformNotifyClients(new NotifyExceptionArgs(ex));}}}
}

Sink简单地异步或同步被接收的消息通知客户端或客户端。它还会生成通知异常和服务器异常。

注意:如果通知是同步的,服务器会被阻塞,直到客户端将控制权交还。

客户端实现

客户端实现如下所示:

namespace TestClient
{/// <summary>/// Class to manage a TestClient/// </summary>public class TestClient : IDisposable{private Delay _delay;private RemoteConnector<ITestInterface> _remoteConnector;private Guid ClientID => _remoteConnector.ClientID;private ITestInterface TestProvider => _remoteConnector.RemoteObject;public RemoteState RemoteState => _remoteConnector.RemoteState;/// Dispose this objectpublic void Dispose(){_remoteConnector?.Dispose();}/// <summary>/// Initialize a remote connector to the server giving the channel./// </summary>/// <param name="channel">The channel.</param>public void Initialize(IChannel channel){// instantiate the client_remoteConnector = new RemoteConnector<ITestInterface>(new CHANNEL());_remoteConnector.Callback += OnRemoteCallback;_remoteConnector.RemoteStateChanged += OnRemoteStateChanged;}/// <summary>/// Notification from the server to the client./// </summary>/// <param name="sender">The sender is the client ID.</param>/// <param name="e">The event argument.</param>private void OnRemoteCallback(object sender, EventArgs e){// is notification for me ?if ((Guid)sender != ClientID)return;// the server sends me a messageif (e is TestMessageArgs args1)Console.WriteLine("Message from Server: " + args1.Message);// the server sends me an exceptionelse if (e is NotifyExceptionArgs args2)Console.WriteLine("Exception from Server: " + args2.Exception.Message);}/// <summary>/// Notification when the remote connection is changed./// </summary>/// <param name="sender">The sender.</param>/// <param name="remoteState">The new remote state.</param>private void OnRemoteStateChanged(object sender, RemoteState remoteState){switch (remoteState){case RemoteState.Connected:Console.WriteLine("RemoteState: [" + RemoteState +"] Client [" + ClientID +"] Delay [" + _delay.TotalMilliseconds + "] ms");// execute commands on the serverExecuteCommandsOnServer();break;default:Console.WriteLine("RemoteState: [" + RemoteState + "]");break;}}/// Starts the connection with the server.public void Start(){if (_remoteConnector == null)throw new ApplicationException("Please call Initialize before Start");_delay = new Delay();_remoteConnector.Start(10); // wait 10s to connect to the server else exception}/// Stops the connection with the server.public void Stop(){_remoteConnector?.Stop();}/// Execute commands on the server.private void ExecuteCommandsOnServer(){// the server will send back notification asynchronously to all clientsfor (int i = 1; i <= 3; i++){TestProvider.Execute("Hello TestServer all #" + i);Thread.Sleep(500);}// the server will send back notification asynchronously to mefor (int i = 1; i <= 3; i++){TestProvider.Execute(ClientID, "Hello TestServer me #" + i);Thread.Sleep(500);}// the server will send back notification synchronously to all clientfor (int i = 1; i <= 3; i++){TestProvider.ExecuteSync("Hello TestServer Sync all #" + i);Thread.Sleep(500);}// the server will generate an exceptiontry{TestProvider.ExecuteException();}catch (Exception ex){Console.WriteLine("** Server exception: " + ex.Message);}// execute method on the server, the server will notify an exceptionTestProvider.ExecuteNotifyException();}}
}

这个TestClient类就像一个控制器。它实现了RemoteConnector<ITestInterface>以连接到服务器。远程连接器提供来自服务器的ITestInterface作为TestProvider、服务器Callback事件、来自连接器的RemoteStateChanged事件和客户端ID。它必须实现IDisposable接口以释放远程连接器,因为远程连接器有一个工作线程来连接或重新连接到服务器。

该Start()方法连接到服务器。在这个例子中,它会等待最多10秒直到建立连接,但也可以等待更长时间或不等待(参数= 0)。一旦连接准备好,将生成一个带有RemoteState.Connected参数的RemoteStateChanged事件。该Delay对象通知有关连接的持续时间。准备就绪后,将执行客户端代码ExecuteCommandsOnServer(),但这仅作为示例。客户端可以在任何地方执行服务器调用。

该OnRemoteCallback(..)事件检查通知是否适合我。服务器可以根据需要向指定的客户端发送通知。如果连接了多个客户端,服务器会向所有客户端广播通知。

如何测试示例

要测试远程处理框架,请启动客户端和服务器,停止并重新启动客户端或服务器,然后查看客户端或服务器如何自动重新连接。

本文中的项目

通用客户端——服务器 DotNet 远程项目

此测试示例的项目是:

  • FW.Remoting:通用的客户端——服务器 DotNet 远程处理组件
  • TestLibrary:服务器和客户端测试项目的公共库
  • TestServer: 服务器项目
  • TestClient: 客户项目
  • TestClientServer:启动服务器和3个客户端的应用程序

其他框架项目

这些组件将在其他出版物中描述。

  • FW.Common: 通用组件
  • FW.Diagnostics:使用log4net和/或DbgView的所有类型项目的诊断组件
  • FW.WinApi:访问Windows API的通用组件
  • FW.WinForm:Winform应用程序的通用组件

LogViewer WinForm应用程序

显示Test应用程序生成的xlog文件的Log4Net简单查看器。此查看器将在另一份发布版本中进行描述。

结论

如果您需要与服务器回调进行强大的客户端——服务器远程通信,那么这个框架就是您所需要的!

https://www.codeproject.com/Articles/5296049/Generic-Client-Server-DotNet-Remoting-with-Server

带有服务器回调的通用客户端——服务器 DotNet远程处理相关推荐

  1. 客户端/服务器程序_了解客户端/服务器协议和Web应用程序

    客户端/服务器程序 Introduction 介绍 HyperText Transfer Protocol or "HTTP" is the underpinning of int ...

  2. c 服务器文件是存在,客户端服务器在较大的文件的c文件传输问题

    下面的代码适用于最后一个数据包包含的数据少于最大长度的较小文件,该功能通过显示接收到的文件正确退出. 如果传输的文件的最后一个数据包或缓冲区包含与我的情况下接收缓冲区阵列512的大小相同的确切数量.然 ...

  3. ktv服务器操作系统,开源ktv客户端服务器系统

    开源ktv客户端服务器系统 内容精选 换一换 专享版Kafka实例完全兼容开源Kafka协议,可以直接使用kafka开源客户端连接.如果使用SASL认证方式,则在开源客户端基础上使用云服务提供的证书文 ...

  4. rtx服务器设置 文件,rtx 客户端 服务器设置 配置文件

    rtx 客户端 服务器设置 配置文件 内容精选 换一换 该操作指导安装工程师在集群及Flume服务安装完成后,分别配置Flume服务的服务端和客户端参数,使其可以正常工作.本章节适用于MRS 3.x及 ...

  5. 华为服务器网卡激活配置文件,客户端服务器网络配置文件

    客户端服务器网络配置文件 内容精选 换一换 在进行应用开发时,要准备的开发和运行环境如表1所示.进行应用开发时,需要同时准备代码的运行调测的环境,用于验证应用程序运行正常.如果使用Linux环境调测程 ...

  6. cf虚拟服务器设置方法,cf客户端 服务器 连接

    cf客户端 服务器 连接 内容精选 换一换 DCS缓存实例支持域名访问后,若客户端无法使用域名连接DCS缓存实例,需要将租户子网的DNS服务地址配置为内网域名服务器地址.具体配置方法请参考修改VPC子 ...

  7. ASP.NET AJAX(服务器回调)

    如果只用纯粹的 js ,你必须弥补 ASP.NET 服务器端抽象和有限的 HTML DOM 之间的鸿沟,这不简单,没有 VS 的智能提示和调试工具,编写无错的代码和诊断错误都非常困难.由于各种突发事件 ...

  8. 微软服务器 客户机,网络客户端和服务器技术简介

    网络客户端和服务器技术简介 已完成 7 分钟 关于网络的组成,你首先需要了解网络的构建方式. 服务器是网络的骨干. 通过混合使用集线器.交换机和路由器,可在整个网络中实现连接. 此知识适用于自己组织的 ...

  9. 远程PLC监控调试,PLC通用中转服务器,多客户端tcp中转服务器源代码

    远程PLC监控调试,PLC通用中转服务器,多客户端tcp中转服务器源代码,socket多线程并发通讯,对接多路plc串口WIFI模块实现远程调试程序.支持各种串口服务器以及tcp以太网转发器硬件. 编 ...

最新文章

  1. eclipse关闭mysql数据库,有关于用eclipse连接mysql数据库出现的问题以及解决办法
  2. 列出所有已安装的perl模块
  3. oracle 11g duplicate active database 建立物理DG
  4. 1种策略就能控制多类模型,华人大二学生提出RL泛化方法,LeCun认可转发 | ICML 2020...
  5. win7 安装好redis 如何安装扩展
  6. SCI论文写作中常见的语言问题汇总
  7. iOS-UICollectionView
  8. 详解Class类文件的结构(下)
  9. flask中数据库迁移
  10. 三维重建笔记——Linux环境下openMVG的安装
  11. Photoshop 2023(版本24.0)新增功能和软件下载
  12. WIFI和路由器密码破解的方法
  13. 不知道免费去水印图片软件哪个好?来看看这3个软件
  14. Java: Unresolved compilation problem的解决方法
  15. 如何解决安装或者卸载时 临时文件夹已满或不能访问
  16. 什么是RST包,什么是三次握手,什么是四次握手 ---请进
  17. 推荐 25 个优雅的 jQuery Tooltip 插件
  18. 以计件积分为纽带-探索客户中心团队再造模式
  19. Impala服务:unable to find SASL plugin: PLAIN
  20. 【软件测试技术】黑盒测试步骤设计详解

热门文章

  1. signature pad java_2020-07-08 JSsignature_pad 无纸化电子签名
  2. anyview下载java,下载AnyviewMobile Games Java - 596763 - ebook txt Anyview | mobile9
  3. python把字符串3des加密_Python干货之六大密码学编程库
  4. axure删除的页面怎么恢复_微信删除好友怎么找回?快速恢复,真的不难
  5. git 提交代码命令_提交代码:git push 命令的四种形式
  6. 日料美食海鲜精品海报PSD分层模板,美味势不可挡
  7. UI实用案例|黄金分割在界面设计中的应用
  8. 设计干货栅格系统素材 | UI设计师应用好帮手
  9. UI设计师应该知道的汉字体种类的用途(免费素材)
  10. apache缓存php页面不改变,Apache服务器禁止静态文件缓存的实现方法