首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用mORMot框架在服务器和客户端之间发送消息

使用mORMot框架在服务器和客户端之间发送消息
EN

Stack Overflow用户
提问于 2015-04-05 21:18:07
回答 1查看 3.9K关注 0票数 2

mORMot框架(www.synopse.info)增加了对WebSockets的支持,在包中还有一个关于WebSockets的演示(示例31)。在此示例中,客户端向服务器发送一条消息,并向客户端发送一条新消息。我想用这个库来做这个:

  1. 客户端向服务器发送消息,并发送IP地址(无需等待服务器消息);
  2. 服务器可以通过IP地址向单个客户端发送消息;

注意: IP地址仅用于标识客户端。我也可以用一个独特的名字。

类似于客户端和服务器之间的局域网聊天。我不明白如何编辑第31号样本来完成它。此示例基于接口。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-04-06 11:19:18

不需要存储IP或任何低级实现参数(顺便说一句,IP无法以独特的方式识别连接:多个客户端可能共享相同的IP)。

在mORMot框架中,异步回调是通过接口参数实现的。在服务器端,这个参数的每个实例实际上都是一个“假”类实例,链接到输入连接,能够通过其接口方法调用客户机。

这是一种非常简单的实现回调的方法--实际上,这是在服务器端实现实体回调的好方法,mORMot框架允许使用WebSockets以客户机/服务器的方式发布此机制。

因此,首先定义回调接口和服务接口:

代码语言:javascript
复制
  IChatCallback = interface(IInvokable)
    ['{EA7EFE51-3EBA-4047-A356-253374518D1D}']
    procedure BlaBla(const pseudo, msg: string);
  end;

  IChatService = interface(IInvokable)
    ['{C92DCBEA-C680-40BD-8D9C-3E6F2ED9C9CF}']
    procedure Join(const pseudo: string; const callback: IChatCallback);
    procedure BlaBla(const pseudo,msg: string);
    procedure CallbackReleased(const callback: IInvokable);
  end;

然后,在服务器端,每次对IChatService.Join()的调用都会订阅一个内部连接列表:

代码语言:javascript
复制
  TChatService = class(TInterfacedObject,IChatService)
  protected
    fConnected: array of IChatCallback;
  public
    procedure Join(const pseudo: string; const callback: IChatCallback);
    procedure BlaBla(const pseudo,msg: string);
    procedure CallbackReleased(const callback: IInvokable);
  end;

procedure TChatService.Join(const pseudo: string;
  const callback: IChatCallback);
begin
  InterfaceArrayAdd(fConnected,callback);
end;

然后,应该通过调用IChatService.BlaBla()方法向所有连接的客户端广播对IChatCallback.BlaBla()方法的远程调用:

代码语言:javascript
复制
procedure TChatService.BlaBla(const pseudo,msg: string);
var i: integer;
begin
  for i := 0 to high(fConnected) do
    fConnected[i].BlaBla(pseudo,msg);
end;

请注意,对IChatCallback.BlaBla()的所有循环调用都将通过WebSockets以异步和非阻塞的方式进行,这样即使在大量客户机的情况下,IChatService.BlaBla()方法也不会阻塞。在消息数量较多的情况下,框架甚至能够将通知消息推送到单个消息中,以减少资源的使用。

当释放客户端回调实例时(显式地,或者如果连接中断),服务器将调用以下方法,因此可以用于取消订阅通知:

代码语言:javascript
复制
procedure TChatService.CallbackReleased(const callback: IInvokable);
begin
  InterfaceArrayDelete(fConnected,callback);
end;

在服务器端,您将服务定义为:

代码语言:javascript
复制
  Server.ServiceDefine(TChatService,[IChatService],sicShared).
    SetOptions([],[optExecLockedPerInterface]);

在这里,已经设置了optExecLockedPerInterface选项,以便所有方法调用都是线程安全的,因此并发访问内部fConnected[]列表是安全的。

在客户端,您实现了IChatCallback回调接口:

代码语言:javascript
复制
type
  TChatCallback = class(TInterfacedCallback,IChatCallback)
  protected
    procedure BlaBla(const pseudo, msg: string);
  end;

procedure TChatCallback.BlaBla(const pseudo, msg: string);
begin
  writeln(#13'@',pseudo,' ',msg);
end;

然后以这样的方式订阅远程服务:

代码语言:javascript
复制
var Service: IChatService;
    callback: IChatCallback;
...
    Client.ServiceDefine([IChatService],sicShared);
    if not Client.Services.Resolve(IChatService,Service) then
      raise EServiceException.Create('Service IChatService unavailable');
...
      callback := TChatCallback.Create(Client,IChatCallback);
      Service.Join(pseudo,callback);
...
    try
      repeat
        TextColor(ccLightGray);
        readln(msg);
        if msg='' then
          break;
        Service.BlaBla(pseudo,msg);
      until false;
    finally
      callback := nil;
      Service := nil; // release the service local instance BEFORE Client.Free
    end;

如果您与现有的客户机/服务器SOA解决方案(在Delphi、Java、C#,甚至在Go或其他框架中)进行比较,这种基于接口的回调机制听起来非常独特,而且易于使用。当然,这项工作从Delphi6到XE7,以及在Linux下的工作,都要感谢FPC或CrossKylix。

我已经将完整的示例源代码上载到我们的存储库中,包括服务器端应用程序客户端

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29462334

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档