redis實現發佈(訂閱)消息git
什麼是redis的發佈訂閱(pub/sub)? Pub/Sub功能(means Publish, Subscribe)即發佈及訂閱功能。基於事件的系統中,Pub/Sub是目前普遍使用的通訊模型,它採用事件做爲基本的通訊機制,提供大規模系統所要求的鬆散耦合的交互模式:訂閱者(如客戶端)以事件訂閱的方式表達出它有興趣接收的一個事件或一類事件;發佈者(如服務器)可將訂閱者感興趣的事件隨時通知相關訂閱者。熟悉設計模式的朋友應該瞭解這與23種設計模式中的觀察者模式極爲類似。 github
看到發佈訂閱的特性,用來作一個簡單的實時聊天系統再適合不過了。這是其中之一,固然這樣的東西,咱們開發中不多涉及到。再舉一個經常使用的,在咱們的分佈式架構中,經常會遇到讀寫分離的場景,在寫入的過程當中,就可使用redis發佈訂閱,使得寫入值及時發佈到各個讀的程序中,就保證數據的完整一致性。再好比,在一個博客網站中,有100個粉絲訂閱了你,當你發佈新文章,就能夠推送消息給粉絲們拉。總之場景不少,須要去挖掘。。redis
Redis的pub/sub是一種消息通訊模式,主要的目的是解除消息發佈者和消息訂閱者之間的耦合, Redis做爲一個pub/sub的server, 在訂閱者和發佈者之間起到了消息路由的功能。express
Redis 發佈訂閱(pub/sub)是一種消息通訊模式:發送者(pub)發送消息,訂閱者(sub)接收消息。apache
Redis 客戶端能夠訂閱任意數量的頻道。json
當有新消息經過 PUBLISH 命令發送給頻道 channel1 時, 這個消息就會被髮送給訂閱它的全部客戶端。設計模式
// *************************************************************************** } // // Delphi REDIS Client // // Copyright (c) 2015-2017 Daniele Teti // // https://github.com/danieleteti/delphiredisclient // // *************************************************************************** // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // *************************************************************************** unit MainForm; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, redis.client, redis.commons, redis.netlib.indy, System.threading, Vcl.StdCtrls; type TForm2 = class(TForm) Memo1: TMemo; Edit2: TEdit; Label1: TLabel; Button1: TButton; procedure FormCreate(Sender: TObject); procedure Edit2KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure Button1Click(Sender: TObject); private _redis: IRedisClient; FTask: ITask; FClosing: Boolean; procedure SendChatMessage; procedure OnMessage(const ANickName, AMessage: string); { Private declarations } public { Public declarations } end; var Form2: TForm2; implementation uses System.json, ShellAPI; {$R *.dfm} procedure TForm2.Button1Click(Sender: TObject); begin ShellExecute(0, pchar('open'), pchar(Application.ExeName), nil, nil, SW_SHOW); end; procedure TForm2.Edit2KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key = VK_RETURN then begin SendChatMessage; Key := 0; Edit2.Clear; end; end; procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin FClosing := True; end; procedure TForm2.FormCreate(Sender: TObject); begin FClosing := False; Label1.Caption := InputBox('Chat user name', 'What is your user name in this chat?', 'd.teti' + (100 + Random(999)) .ToString); _redis := NewRedisClient(); FTask := TTask.Run( procedure var r: IRedisClient; begin r := NewRedisClient; r.SUBSCRIBE(['chat'], procedure(channel, message: string) var jobj: TJSONObject; msg, nickname: string; begin jobj := TJSONObject.ParseJSONValue(message) as TJSONObject; nickname := jobj.GetValue<TJSONString>('nickname').Value; msg := jobj.GetValue<TJSONString>('message').Value; TThread.Synchronize(nil, procedure begin Self.OnMessage(nickname, msg); end); end, function: Boolean begin Result := Assigned(Self) and (not FClosing); end); end); end; procedure TForm2.OnMessage(const ANickName, AMessage: string); begin Memo1.Lines.Add('[' + ANickName + '] ' + DateTimeToStr(now)); Memo1.Lines.Add(AMessage); Memo1.Lines.Add('---'); end; procedure TForm2.SendChatMessage; var jobj: TJSONObject; begin jobj := TJSONObject.Create; try jobj.AddPair('nickname', Label1.Caption).AddPair('message', Edit2.Text); _redis.PUBLISH('chat', jobj.ToString); finally jobj.Free; end; end; end.