1、簡介
Socket.D 是基於"事件"和"語義消息""流"的網絡應用層協議。底層可以依賴 TCP、UDP、KCP、WebSocket 等傳輸層協議。其開發背後的動機是用開銷更少的協議取代超文本傳輸協議(HTTP),HTTP 協議對於許多任務(如微服務通信)來說效率低下。
2、Socket.D 的集羣應用
在 Socket.D 的集羣故事裏,會有三個角色:
- 請求者
- 經理人(或者中間人)
- 響應者
客戶端通過 url 連接經理人後,就會成爲集羣的一部分。它可以是請求者,也可以是響應者。
sd:tcp://127.0.0.1:8602?@=demoapp
url 會包括:
- 協議頭(sd 表示 socket.d 協議,tcp 表示傳輸方案)
- 地址與端口
- 路徑
- 還有
@
參數,這個參數會申明自己的應用名字。連接經理人時,也相當於完成身份註冊了。
在集羣內部,相互間通過 At
進行發起向“響應者”的請求。就像:
session.send("test", new StringEntity("hello").at("demoapp"));
3、集羣的四種轉發
在集羣的活動中,請求者會發消息給經理人,經理人根據 at name 再轉發給相應的響應者。
- 四種轉發方式(單播,單播!,組播,廣播):
at | 描述 | 備註 |
---|---|---|
demoapp |
單播 | 給叫這個名的其中一個會話發(使用 平均輪詢 “負載均衡”策略) |
demoapp! |
單播! | 給叫這個名的其中一個會話發(使用 ip_hash “負載均衡”策略) |
demoapp* |
組播 | 給叫這個名的整組會話發(如果自己也叫這個名,則自己除外) |
* |
廣播 | 給集羣裏的全部會話發(自己除外) |
- 通過at方式進行轉發,示例:
session.send("test", new StringEntity("hello").at("demoapp"));
session.send("test", new StringEntity("hello").at("demoapp!"));
session.send("test", new StringEntity("hello").at("demoapp*"));
session.send("test", new StringEntity("hello").at("*"));
4、演示
假設經理人(或者中間人) 的服務地址爲:127.0.0.1:8602。下面以 Java 語言展示效果:
- 創建經理人
public class BrokerDemo {
public static void main(String[] args) throws Exception {
SocketD.createServer("sd:tcp")
.config(c -> c.port(8602).fragmentHandler(new BrokerFragmentHandler()))
.listen(new BrokerListener())
.start();
}
}
- 創建響應者(自己不需要端口啓動,連接經理人後即可提供服務)
public class ResponderDemo {
public static void main(String[] args) throws Exception {
//連接到 broker ,並給自己命名爲:demoapp
ClientSession session = SocketD.createClient("sd:tcp://127.0.0.1:8602?@=demoapp")
.listen(new EventListener().doOn("/hello", (s,m)->{
//監聽 "/hello" 事件,如果是請求則答覆
if(m.isRequest()){
s.reply(m, new StringEntity("me too!"));
}
}))
.open();
}
}
- 創建請求者
public class RequesterDemo {
public static void main(String[] args) throws Exception {
//連接到 broker ,並給自己命名爲:demotester
ClientSession session = SocketD.createClient("sd:tcp://127.0.0.1:8602?@=demotester")
.open();
//發送消息,並要求轉發給 "demoapp"
session.sendAndRequest("/hello", new StringEntity("").at("demoapp")).thenReply(r->{
//收到答覆後,打印結果
print(r.dataAsString());
});
}
}