点击或拖拽改变大小

MqttServer 类

一个Mqtt的服务器类对象,本服务器支持发布订阅操作,支持从服务器强制推送数据,支持往指定的客户端推送,支持基于一问一答的远程过程调用(RPC)的数据交互,支持文件上传下载。根据这些功能从而定制化出满足各个场景的服务器,详细的使用说明可以参见代码api文档示例。
An Mqtt server class object. This server supports publish and subscribe operations, supports forced push data from the server, supports push to designated clients, supports data interaction based on one-question-one-answer remote procedure calls (RPC), and supports file upload and download . According to these functions, the server can be customized to meet various scenarios. For detailed instructions, please refer to the code api document example.
继承层次
SystemObject
  HslCommunication.Core.NetCommunicationTcpServer
    HslCommunication.MQTTMqttServer

命名空间:  HslCommunication.MQTT
程序集:  HslCommunication (在 HslCommunication.dll 中) 版本:12.3.1.0 (12.3.1.0)
语法
public class MqttServer : CommunicationTcpServer, IDisposable

MqttServer 类型公开以下成员。

构造函数
  名称说明
公共方法MqttServer
实例化一个MQTT协议的服务器
Instantiate a MQTT protocol server
Top
属性
  名称说明
公共属性DownloadFileRedirect
可以自定义重新指向需要下载的文件路径信息,第一个参数是下载文件名称,第个参数是实际映射名称,需要返回新的文件路径和下载完成是否删除的信息
You can customize the redirection of the file path that needs to be downloaded. The first parameter is the name of the downloaded file,
公共属性EnableIPv6
获取或设置服务器是否支持IPv6的地址协议信息
Get or set whether the server supports IPv6 address protocol information
(继承自 CommunicationTcpServer。)
公共属性IsStarted
服务器引擎是否启动
Whether the server engine is started
(继承自 CommunicationTcpServer。)
公共属性LogDebugMessage
记录一些调试日志的委托,将会进行输出调试文本。
The delegate that records some debug logs will output debug text.
(继承自 CommunicationTcpServer。)
公共属性代码示例LogNet
组件的日志工具,支持日志记录,只要实例化后,当前网络的基本信息,就以DEBUG等级进行输出
The component's logging tool supports logging. As long as the instantiation of the basic network information, the output will be output at DEBUG
(继承自 CommunicationTcpServer。)
公共属性LogStatistics
获取当前的日志统计信息,可以获取到每个API的每天的调度次数信息,缓存60天数据,如果需要存储本地,需要调用SaveToFile(String)方法。
Get the current log statistics, you can get the daily scheduling times information of each API, and cache 60-day data. If you need to store it locally, you need to call the SaveToFile(String) method.
公共属性MqttOnlineSessions
获得当前异步客户端在线的MQTT客户端信息。
Get the MQTT client information of the current asynchronous client online.
公共属性OnlineCount
获取当前的在线的客户端数量
Gets the number of clients currently online
公共属性OnlineSessions
获得当前所有的在线的MQTT客户端信息,包括异步的客户端及同步请求的客户端。
Obtain all current online MQTT client information, including asynchronous client and synchronous request client.
公共属性Port
获取或设置服务器的端口号,如果是设置,需要在服务器启动前设置完成,才能生效。
Gets or sets the port number of the server. If it is set, it needs to be set before the server starts to take effect.
(继承自 CommunicationTcpServer。)
公共属性SocketKeepAliveTime
获取或设置客户端的Socket的心跳时间信息,这个是Socket底层自动实现的心跳包,不基于协议层实现。默认小于0,不开启心跳检测,如果需要开启,设置 60_000 比较合适,单位毫秒
Get or set the heartbeat time information of the Socket of the client. This is the heartbeat packet automatically implemented by the bottom layer of the Socket, not based on the protocol layer. The default value is less than 0, and heartbeat detection is not enabled. If you need to enable it, it is more appropriate to set 60_000, in milliseconds.
(继承自 CommunicationTcpServer。)
公共属性SyncOnlineSessions
获得当前同步客户端在线的MQTT客户端信息,如果客户端是短连接,将难以捕获在在线信息。
Obtain the MQTT client information of the current synchronization client online. If the client is a short connection, it will be difficult to capture the online information.
公共属性TopicStatistics
获取或设置当前的主题统计信息,默认按照天进行统计,连续统计30天。
You can obtain or set the statistics of the current topic. By default, the statistics are collected every day for 30 consecutive days.
公共属性TopicWildcard
获取或设置是否启用订阅主题通配符的功能,默认为 False
Gets or sets whether to enable the function of subscribing to the topic wildcard, the default is False
Top
方法
  名称说明
公共方法CloseFileServer
关闭文件服务功能
受保护的方法DeleteFileByName
删除一个指定的文件,如果文件不存在,直接返回 True,如果文件存在则直接删除,删除成功返回 True,如果发生了异常,返回False
Delete a specified file, if the file does not exist, return True directly, if the file exists, delete it directly, if the deletion is successful, return True, if an exception occurs, return False
公共方法DeleteRetainTopic
删除服务器里的指定主题的驻留消息。
Delete the resident message of the specified topic in the server.
公共方法Dispose
Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
受保护的方法Dispose(Boolean)
释放当前的对象
公共方法Equals
Determines whether the specified object is equal to the current object.
(继承自 Object。)
受保护的方法ExtraOnClose
关闭的时候额外执行的功能代码
(重写 CommunicationTcpServerExtraOnClose.)
受保护的方法ExtraOnStart
服务器启动的时候额外执行的功能代码
(重写 CommunicationTcpServerExtraOnStart.)
受保护的方法Finalize
Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection.
(继承自 Object。)
公共方法GetAllMqttRpcApiInfo
获取当前所有注册的RPC接口信息,将返回一个数据列表。
Get all currently registered RPC interface information, and a data list will be returned.
公共方法GetAllRetainTopics
获取所有的驻留的消息的主题,如果消息发布的时候没有使用Retain属性,就无法通过本方法查到
Get the subject of all resident messages. If the Retain attribute is not used when the message is published, it cannot be found by this method
公共方法GetGroupFromFilePath
根据路径信息获取到文件列表管理容器,如果返回空,表示不存在。
The file list management container is obtained according to the path information. If the return is empty, it means that it does not exist.
公共方法GetHashCode
Serves as the default hash function.
(继承自 Object。)
公共方法GetMonitorItemsSnapShoot
获取当前实时的文件上传下载的监控信息,操作的客户端信息,文件分类,文件名,上传或下载的速度等
Obtain current real-time file upload and download monitoring information, operating client information, file classification, file name, upload or download speed, etc.
公共方法GetMqttSessionsByTopic
获取订阅了某个主题的所有的会话列表信息
Get all the conversation list information subscribed to a topic
公共方法GetTrustedClients
获取受信任的客户端列表
Get a list of trusted clients
(继承自 CommunicationTcpServer。)
公共方法GetType
Gets the Type of the current instance.
(继承自 Object。)
公共方法GroupFileContainerCount
获取当前的针对文件夹的文件管理容器的数量
Get the current number of file management containers for the folder
受保护的方法LogDebugMsg
记录当前的日志信息
(继承自 CommunicationTcpServer。)
受保护的方法MemberwiseClone
Creates a shallow copy of the current Object.
(继承自 Object。)
公共方法PublishAllClientTopicPayload
向所有的客户端强制发送主题及负载数据,默认消息不驻留
Send subject and payload data to all clients compulsively, and the default message does not retain
公共方法PublishTopicPayload(String, Byte, Boolean)
从服务器向订阅了指定的主题的客户端发送消息,默认消息不驻留
Sends a message from the server to a client that subscribes to the specified topic; the default message does not retain
公共方法PublishTopicPayload(MqttSession, String, Byte)
向指定的客户端发送主题及负载数据
Sends the topic and payload data to the specified client
公共方法PublishTopicPayload(String, Byte, Boolean, FuncMqttSession, Boolean)
使用指定的规则向客户端发布主题及负载数据,可以根据会话的登录用户名,客户端ID信息进行筛选,例如只发布用户名admin的账户:( session ) => session.UserName == "admin"
Use the specified rules to publish topic and load data to the client, which can be filtered according to the session login user name and client ID information. For example, only the account with the user name admin is published: ( session ) => session.UserName == "admin"
公共方法PublishTopicPayload(String, String, Byte, Boolean)
向指定的客户端ID强制发送消息,默认消息不驻留
Forces a message to the specified client ID, and the default message does not retain
公共方法RegisterMqttRpcApi(Object)
注册一个RPC的服务接口,可以指定当前的控制器名称,以及提供RPC服务的原始对象
Register an RPC service interface, you can specify the current controller name, and the original object that provides the RPC service
公共方法RegisterMqttRpcApi(String, Object)
注册一个RPC的服务接口,可以指定当前的控制器名称,以及提供RPC服务的原始对象
Register an RPC service interface, you can specify the current controller name, and the original object that provides the RPC service
公共方法RegisterMqttRpcApi(String, Object, HslMqttPermissionAttribute)
注册一个RPC的服务接口,可以指定当前的控制器名称,以及提供RPC服务的原始对象,指定统一的权限控制。
Register an RPC service interface, you can specify the current controller name, and the original object that provides the RPC service, Specify unified access control
公共方法RemoveAndCloseSession
让MQTT客户端正常下线,调用本方法即可自由控制会话客户端强制下线操作。
公共方法ReportObjectApiMethod
使用指定的对象来返回网络的API接口,前提是传入的数据为json参数,返回的数据为 OperateResult<string> 数据,详细参照说明
Use the specified object to return the API interface of the network, provided that the incoming data is json parameters and the returned data is OperateResult<string> data, please refer to the description for details
公共方法ReportOperateResult(MqttSession, OperateResultString)
向客户端发布一个操作结果的信息,仅用于同步网络的时候反馈操作结果,该操作可能成功,可能失败,客户端就知道服务器发生了什么,以及结果如何。
Publish an operation result information to the client, which is only used to feed back the operation result when synchronizing the network. The operation may succeed or fail, and the client knows what happened to the server and the result.
公共方法ReportOperateResult(MqttSession, String)
向客户端发布一个失败的操作信息,仅用于同步网络的时候反馈失败结果,将错误的信息反馈回客户端,客户端就知道服务器发生了什么,为什么反馈失败。
Publish a failed operation information to the client, which is only used to feed back the failure result when synchronizing the network. If the error information is fed back to the client, the client will know what happened to the server and why the feedback failed.
公共方法ReportProgress
向客户端发布一个进度报告的信息,仅用于同步网络的时候才支持进度报告,将进度及消息发送给客户端,比如你的服务器需要分成5个部分完成,可以按照百分比提示给客户端当前服务器发生了什么
Publish the information of a progress report to the client. The progress report is only supported when the network is synchronized. The progress and the message are sent to the client. For example, your server needs to be divided into 5 parts to complete. You can prompt the client according to the percentage. What happened to the server
受保护的方法ReturnAbsoluteFileName
返回服务器的绝对路径,包含根目录的信息 [Root Dir][A][B][C]...[FileName] 信息
公共方法ServerClose
关闭服务器的引擎
Shut down the server's engine
(继承自 CommunicationTcpServer。)
公共方法ServerStart
指定端口号来启动服务器的引擎
Specify the port number to start the server's engine
(继承自 CommunicationTcpServer。)
公共方法ServerStart(Int32)
指定端口号来启动服务器的引擎
Specify the port number to start the server's engine
(继承自 CommunicationTcpServer。)
公共方法SetSslPipeAction
设置一个SSL的管道操作对象,在管道实例化之后,可以进行一些初始化的属性设置,例如自定义 SslProtocols 枚举
(继承自 CommunicationTcpServer。)
公共方法SetTrustedIpAddress
设置并启动受信任的客户端登录并读写,如果为null,将关闭对客户端的ip验证
Set and start the trusted client login and read and write, if it is null, the client's IP verification will be turned off
(继承自 CommunicationTcpServer。)
受保护的方法SocketAcceptExtraCheck
当客户端的socket登录的时候额外检查的操作,并返回操作的结果信息。
The operation is additionally checked when the client's socket logs in, and the result information of the operation is returned.
(继承自 CommunicationTcpServer。)
受保护的方法ThreadPoolLogin
当客户端连接到服务器,并听过额外的检查后,进行回调的方法
Callback method when the client connects to the server and has heard additional checks
(重写 CommunicationTcpServerThreadPoolLogin(PipeTcpNet, IPEndPoint).)
公共方法ToString
Returns a string that represents the current object.
(重写 ObjectToString.)
公共方法UnRegisterHttpRpcApiSingle
卸载一个指定的RPC接口,需要指定唯一的接口名称,如果接口重命名了,需要使用实际访问的时候的接口名称,返回是否成功卸载接口
To uninstall a specified RPC interface, you need to specify a unique interface name. If the interface is renamed, you need to use the interface name during the actual access, and return whether the interface is successfully uninstalled
公共方法UnRegisterMqttRpcApi(Object)
卸载一个已经注册的RPC接口,想要卸载指定的接口,此处就需要传入注册时一样的参数
Uninstall a registered RPC interface. If you want to uninstall the specified interface, you need to pass in the same parameters as the registration
公共方法UnRegisterMqttRpcApi(String, Object)
卸载一个已经注册的RPC接口,想要卸载指定的接口,此处就需要传入注册时一样的参数
Uninstall a registered RPC interface. If you want to uninstall the specified interface, you need to pass in the same parameters as the registration
公共方法UseFileServer
启动文件服务功能,协议头为FILE,需要指定服务器存储的文件路径
Start the file service function, the protocol header is FILE, you need to specify the file path stored by the server
公共方法UseSSL(X509Certificate)
使用SSL通信,传递一个证书的对象
(继承自 CommunicationTcpServer。)
公共方法UseSSL(String, String)
使用SSL通信,传递一个证书的路径,以及证书的密码
(继承自 CommunicationTcpServer。)
Top
事件
  名称说明
公共事件ClientVerification
当客户端连接时,触发的验证事件
Validation event triggered when the client connects
公共事件FileOperateVerification
当客户端进行文件操作时,校验客户端合法性的事件,操作码具体查看的常量值
When client performing file operations, it is an event to verify the legitimacy of the client. For the operation code, check the constant value of
公共事件OnClientApplicationMessageReceive
当收到客户端发来的MqttClientApplicationMessage消息时触发
Triggered when a MqttClientApplicationMessage message is received from the client
公共事件OnClientConnected
Mqtt的客户端连接上来时触发
Triggered when Mqtt client connects
公共事件OnClientDisConnected
Mqtt的客户端下线时触发
Triggered when Mqtt client connects
公共事件OnFileChangedEvent
文件变化的事件,当文件上传的时候,文件下载的时候,文件被删除的时候触发。
The file change event is triggered when the file is uploaded, when the file is downloaded, or when the file is deleted.
Top
字段
  名称说明
受保护的字段socketServer
核心的socket服务器
(继承自 CommunicationTcpServer。)
Top
扩展方法
  名称说明
公共扩展器方法ToJsonString
获取当前对象的JSON格式表示的字符串。
Gets the string represented by the JSON format of the current object.
(由 HslExtension 定义。)
Top
备注
本MQTT服务器功能丰富,可以同时实现,用户名密码验证,在线客户端的管理,数据订阅推送,单纯的数据收发,心跳检测,订阅通配符,同步数据访问,文件上传,下载,删除,遍历,详细参照下面的示例说明
通配符请查看TopicWildcard属性,规则参考:http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#appendix-a
示例
最简单的使用,就是实例化,启动服务即可
简单的实例化
MqttServer server;
public void Start( )
{
    try
    {
        server = new MqttServer( );
        server.ServerStart( 1883 );
    }
    catch (Exception ex)
    {
        Console.WriteLine( "Start Failed: " + ex.Message );
    }
}
当然了,我们可以稍微的复杂一点,加一个功能,验证连接的客户端操作
增加验证
MqttServer server;
public void Start( )
{
    try
    {
        server = new MqttServer( );
        server.ClientVerification += ( MqttSession session, string clientId, string userName, string passwrod ) =>
        {
            if (userName == "admin" && passwrod == "123456") return 0;
            return 4;

            // 返回错误码说明 Return error code description
            // 1: unacceptable protocol version
            // 2: identifier rejected
            // 3: server unavailable
            // 4: bad user name or password
            // 5: not authorized
        };
        server.ServerStart( 1883 );
    }
    catch (Exception ex)
    {
        Console.WriteLine( "Start Failed: " + ex.Message );
    }
}
我们可以对ClientID,用户名,密码进行验证,那么我们可以动态修改client id么?比如用户名密码验证成功后,client ID我想设置为权限等级。
动态修改Client ID
server.ClientVerification += ( MqttSession session, string clientId, string userName, string passwrod ) =>
{
    if (userName == "admin" && passwrod == "123456") { session.ClientId = "admin"; return 0; }
    if (userName == "hsl" && passwrod == "123456") { session.ClientId = "GM"; return 0; }  // 也可以写入中文总经理,方便后续其他接口的权限限制
    return 4;

    // 返回错误码说明 Return error code description
    // 1: unacceptable protocol version
    // 2: identifier rejected
    // 3: server unavailable
    // 4: bad user name or password
    // 5: not authorized
};
如果我想强制该客户端不能主动发布主题,可以这么操作。
禁止发布主题
server.ClientVerification += ( MqttSession session, string clientId, string userName, string passwrod ) =>
{
    if (userName == "admin" && passwrod == "123456") { return 0; } // admin 账户允许发布  admin Account allows posting
    if (userName == "hsl" && passwrod == "123456") { session.ForbidPublishTopic = true; return 0; } // 禁止发布 Prohibit posting
    return 4; // 其他账户不允许登录 Other accounts are not allowed to log in

    // 返回错误码说明 Return error code description
    // 1: unacceptable protocol version
    // 2: identifier rejected
    // 3: server unavailable
    // 4: bad user name or password
    // 5: not authorized
};
你也可以对clientid进行过滤验证,只要结果返回不是0,就可以了。接下来我们实现一个功能,所有客户端的发布的消息在控制台打印出来,
打印所有发布
MqttServer server;
public void Start( )
{
    try
    {
        server = new MqttServer( );
        server.ClientVerification += ( MqttSession session, string clientId, string userName, string passwrod ) =>
        {
            if (userName == "admin" && passwrod == "123456") return 0;
            return 4;
        };
        server.OnClientApplicationMessageReceive += ( MqttSession session, MqttClientApplicationMessage message ) =>
        {
            // 此处举例是打印,当然了,你也可以做一些其他的处理,当所有的客户端进行发布操作的时候,就会触发当前的方法
            // The example here is printing. Of course, you can also do some other processing. When all clients perform publishing operations, the current method will be triggered.
            Console.WriteLine( $"ClientId:[{message.ClientId}] Topic:[{message.Topic}] Payload: {Encoding.UTF8.GetString( message.Payload )}" );

            // 如果你想阻止当前的消息推送给客户端,那么可以按照下面的操作
            // If you want to prevent the current message from being pushed to the client, then you can follow
            message.IsCancelPublish = true;
        };
        server.ServerStart( 1883 );
    }
    catch (Exception ex)
    {
        Console.WriteLine( "Start Failed: " + ex.Message );
    }
}
捕获客户端刚刚上线的时候,方便我们进行一些额外的操作信息。下面的意思就是返回一个数据,将数据发送到指定的会话内容上去
客户端上线信息
MqttServer server;
public void Start( )
{
    try
    {
        server = new MqttServer( );
        server.ClientVerification += ( MqttSession session, string clientId, string userName, string passwrod ) =>
        {
            if (userName == "admin" && passwrod == "123456") return 0;
            return 5;
        };
        server.OnClientApplicationMessageReceive += ( MqttSession session, MqttClientApplicationMessage message ) =>
        {
            // 此处举例是打印,当然了,你也可以做一些其他的处理,当所有的客户端进行发布操作的时候,就会触发当前的方法
            // The example here is printing. Of course, you can also do some other processing. When all clients perform publishing operations, the current method will be triggered.
            Console.WriteLine( $"ClientId:[{message.ClientId}] Topic:[{message.Topic}] Payload: {Encoding.UTF8.GetString( message.Payload )}" );

            // 如果你想阻止当前的消息推送给客户端,那么可以按照下面的操作
            // If you want to prevent the current message from being pushed to the client, then you can follow
            message.IsCancelPublish = true;
        };
        server.OnClientConnected += ( MqttSession session ) =>
        {
            // 当客户端连接上服务器的时候触发,你可以做一些额外的数据处理,或是情况处理。比如发送一条消息出去
            // Triggered when the client connects to the server, you can do some additional data processing or situation processing. Such as sending a message out
            server.PublishTopicPayload( session, "Online", Encoding.UTF8.GetBytes( "Thank you for use hsl" ) );
        };
        server.ServerStart( 1883 );
    }
    catch (Exception ex)
    {
        Console.WriteLine( "Start Failed: " + ex.Message );
    }
}
下面演示如何从服务器端发布数据信息,包括多种发布的方法,消息是否驻留,详细看说明即可
服务器发布
public void button1_Click( object sender, EventArgs e )
{
    // 此处示例是发布给指定的主题
    // The example here is posted to the specified topic
    server.PublishTopicPayload( "Topic", Encoding.UTF8.GetBytes( "Test Data" ) );

    // 此处示例是发布给指定的clientId
    // The example here is posted to the specified clientId
    server.PublishTopicPayload( "ClientId1", "Topic", Encoding.UTF8.GetBytes( "Test Data" ) );

    // 此处的示例是发布给所有的客户端,不管这个客户端有没有订阅相关的主题
    // The example here is published to all clients, regardless of whether the client is subscribed to related topics
    server.PublishAllClientTopicPayload( "Topic", Encoding.UTF8.GetBytes( "Test Data" ) );




    // 如果要消息驻留,意思就是当其他的客户端订阅了驻留的主题,会立即收到一条最后更新的数据内容,那么上面的代码可以修改成下面的形式
    // If you want the message to reside, it means that when other clients subscribe to the resident topic, they will immediately receive a last updated data content, then the above code can be modified into the following form
    server.PublishTopicPayload( "Topic", Encoding.UTF8.GetBytes( "Test Data" ), true );
    server.PublishTopicPayload( "ClientId1", "Topic", Encoding.UTF8.GetBytes( "Test Data" ), true );
    server.PublishAllClientTopicPayload( "Topic", Encoding.UTF8.GetBytes( "Test Data" ), true );
}
下面演示如何支持同步网络访问,当客户端是同步网络访问时,协议内容会变成HUSL,即被视为同步客户端,进行相关的操作,主要进行远程调用RPC,以及查询MQTT的主题列表。
同步访问支持
MqttServer server;
public void Start( )
{
    try
    {
        server = new MqttServer( );
        server.ClientVerification += ( MqttSession session, string clientId, string userName, string passwrod ) =>
        {
            if (userName == "admin" && passwrod == "123456") return 0;
            return 4;
        };
        server.OnClientApplicationMessageReceive += ( MqttSession session, MqttClientApplicationMessage message ) =>
        {
            if (session.Protocol == "MQTT")
            {
                // 正常的MQTT协议的内容,进行发布订阅操作

                // 此处举例是打印,当然了,你也可以做一些其他的处理,当所有的客户端进行发布操作的时候,就会触发当前的方法
                // The example here is printing. Of course, you can also do some other processing. When all clients perform publishing operations, the current method will be triggered.
                Console.WriteLine( $"ClientId:[{message.ClientId}] Topic:[{message.Topic}] Payload: {Encoding.UTF8.GetString( message.Payload )}" );

                // 如果你想阻止当前的消息推送给客户端,那么可以按照下面的操作
                // If you want to prevent the current message from being pushed to the client, then you can follow
                message.IsCancelPublish = true;
            }
            else
            {
                // 同步网络的情况,正常情况都是需要返回信息的,否则客户端就会引发接收超时的异常
                // In the case of synchronous network, the normal situation is to return information, otherwise the client will cause an exception of receiving timeout
                if (message.Topic == "GetA")
                {
                    server.PublishTopicPayload( session, "Success", Encoding.UTF8.GetBytes( "这是你获取的数据A" ) );
                }
                else if (message.Topic == "GetB")
                {
                    server.PublishTopicPayload( session, "Success", Encoding.UTF8.GetBytes( "这是你获取的数据B" ) );
                }
                else
                {
                    // 如果需要返回错误的信息,客户端直接IsSuccess为False,然后这个Message就是下面的字符串
                    // If you need to return wrong information, the client directly IsSuccess is False, and then this Message is the following string
                    server.ReportOperateResult( session, "当前的操作不支持" );
                }
            }
        };
        server.ServerStart( 1883 );
    }
    catch (Exception ex)
    {
        Console.WriteLine( "Start Failed: " + ex.Message );
    }
}
如果需要查看在线信息,可以随时获取OnlineCount属性,如果需要查看报文信息,可以实例化日志,参考日志的说明即可。

针对上面同步网络访问,虽然比较灵活,但是什么都要自己控制,无疑增加了代码的复杂度,举个例子,当你的topic分类很多的时候,已经客户端协议多个参数的时候,需要大量的手动解析的代码, 影响代码美观,而且让代码更加的杂乱,除此之外,还有个巨大的麻烦,服务器提供了很多的topic处理程序(可以换个称呼,暴露的API接口), 客户端没法清晰的浏览到,需要查找服务器代码才能知晓,而且服务器更新了接口,客户端有需要同步查看服务器的代码才行,以及做权限控制也很麻烦。
所以在Hsl里面的MQTT服务器,提供了注册API接口的功能,只需要一行注册代码,你的类的方法自动就会变为API解析,所有的参数都是同步解析的,如果你返回的是 OperateResult<T>类型对象,还支持是否成功的结果报告,否则一律视为json字符串,返回给调用方。
基于MQTT的RPC接口实现
MqttServer server;
SiemensS7Net siemens;

public void Start( )
{
    try
    {
        siemens = new SiemensS7Net( SiemensPLCS.S1200, "127.0.0.1" );

        server = new MqttServer( );
        server.ClientVerification += ( MqttSession session, string clientId, string userName, string passwrod ) =>
        {
            if (userName == "admin" && passwrod == "123456") return 0;
            return 4;
        };
        server.OnClientApplicationMessageReceive += ( MqttSession session, MqttClientApplicationMessage message ) =>
        {
            if (session.Protocol == "MQTT")
            {
                // 正常的MQTT协议的内容,进行发布订阅操作

                // 此处举例是打印,当然了,你也可以做一些其他的处理,当所有的客户端进行发布操作的时候,就会触发当前的方法
                // The example here is printing. Of course, you can also do some other processing. When all clients perform publishing operations, the current method will be triggered.
                Console.WriteLine( $"ClientId:[{message.ClientId}] Topic:[{message.Topic}] Payload: {Encoding.UTF8.GetString( message.Payload )}" );

                // 如果你想阻止当前的消息推送给客户端,那么可以按照下面的操作
                // If you want to prevent the current message from being pushed to the client, then you can follow
                message.IsCancelPublish = true;
            }
            else
            {
                // 同步网络的情况,正常情况都是需要返回信息的,否则客户端就会引发接收超时的异常
                // In the case of synchronous network, the normal situation is to return information, otherwise the client will cause an exception of receiving timeout
                if (message.Topic == "GetA")
                {
                    server.PublishTopicPayload( session, "Success", Encoding.UTF8.GetBytes( "这是你获取的数据A" ) );
                }
                else if (message.Topic == "GetB")
                {
                    server.PublishTopicPayload( session, "Success", Encoding.UTF8.GetBytes( "这是你获取的数据B" ) );
                }
                else
                {
                    // 如果需要返回错误的信息,客户端直接IsSuccess为False,然后这个Message就是下面的字符串
                    // If you need to return wrong information, the client directly IsSuccess is False, and then this Message is the following string
                    server.ReportOperateResult( session, "当前的操作不支持" );
                }
            }
        };

        // 注册当前的服务,当下面所有的带特性HslMqttApi的方法都暴露出来,其中,设备温度仅支持admin账户设定
        // Register the current service, when all the following methods with characteristic HslMqttApi are exposed, 
        // the device temperature only supports the admin account setting
        server.RegisterMqttRpcApi( this );
        server.ServerStart( 1883 );
    }
    catch (Exception ex)
    {
        Console.WriteLine( "Start Failed: " + ex.Message );
    }
}

[HslMqttApi( "启动设备" )]
public OperateResult StartDevice( ) => siemens.Write( "M100.0", true );

[HslMqttApi( "停止设备" )]
public OperateResult StopDevice( ) => siemens.Write( "M100.0", false );

[HslMqttApi( "设置设备的温度信息,当设备处于非工作状态才有效,仅允许admin账户设置" )]
[HslMqttPermission( UserName = "admin" )]
public OperateResult SetTemperature( float temp )
{
    // 此处假设设置PLC的温度,当设备停止的时候才能设备
    var check = siemens.ReadBool( "M100.0" ).Check( m => m == false, "当前的设备状态在运行中,无法设置!" );
    if (!check.IsSuccess) return OperateResult.CreateFailedResult<string>( check );

    return siemens.Write( "M200", temp );
}

[HslMqttApi( "读取设备的温度信息" )]
public OperateResult<float> ReadTemperature( ) => siemens.ReadFloat( "M200" );
如果需要查看在线信息,可以随时获取OnlineCount属性,如果需要查看报文信息,可以实例化日志,参考日志的说明即可。

最后介绍一下文件管理服务是如何启动的,在启动了文件管理服务之后,其匹配的客户端 MqttSyncClient 就可以上传下载,遍历文件了。 而服务器端做的就是启用服务,如果你需要一些更加自由的权限控制,比如某个账户只能下载,不能其他操作,都是可以实现的。更加多的示例参考DEMO程序。
基于MQTT的文件管理服务启动
MqttServer server;
public void Start( )
{
    try
    {
        server = new MqttServer( );
        server.ClientVerification += ( MqttSession session, string clientId, string userName, string passwrod ) =>
        {
            if (userName == "admin" && passwrod == "123456") return 0;
            return 4;

            // 返回错误码说明 Return error code description
            // 1: unacceptable protocol version
            // 2: identifier rejected
            // 3: server unavailable
            // 4: bad user name or password
            // 5: not authorized
        };
        // 启用文件管理服务  Enable file management service
        server.UseFileServer( System.IO.Path.Combine( AppDomain.CurrentDomain.BaseDirectory, "FileServer" ) );
        // 如果需要启用文件管理的权限,就编写 FileOperateVerification 事件
        server.FileOperateVerification += ( MqttSession session, byte code, string[] groups, string[] fileNames ) =>
        {
            // 此处举个例子,如果用户名为空,不允许删除操作,当然了,你可以自定义任何的规则
            if (string.IsNullOrEmpty( session.UserName ))
            {
                if (code == MqttControlMessage.FileDelete) return new OperateResult( "Null name not allowed delete!" );
            }
            return OperateResult.CreateSuccessResult( );
        };
        server.ServerStart( 1883 );
    }
    catch (Exception ex)
    {
        Console.WriteLine( "Start Failed: " + ex.Message );
    }
}
参见