用Zmq實現(xiàn)網(wǎng)關與游戲服全互連
(金慶的專欄)
Zeromq無需bind, connect次序,可以在對方bind之前就connect, 可實現(xiàn)服務器以任意順序啟動。
Zmq有自動重連功能,可實現(xiàn)服務器故障重啟不影響整個系統(tǒng)。
萬神服務器內部連接采用了Zmq, 并可能在未來將客戶端服務器之間的連接也改用為Zmq。
萬神的網(wǎng)關(Gtw,Gateway)與游戲服(Gs, Game Server)之間是M*N的全互連關系。
即M個網(wǎng)關,N個游戲服,每個Gtw連接所有Gs, 每個Gs連接所有Gtw.
采用Zmq的Router-Router模式,Gtw和Gs分別只需一個zmq::socket_t, 就可以實現(xiàn)M*N互連。
Router-Router互連的決竅是至少其中一方須設置ZMQ_IDENTITY.
因為Gs是穩(wěn)定的服務器,數(shù)量固定,所以設為bind方,并設置 ZMQ_IDENTITY.
Gtw是可任意添加的服務器,所以設為connect方,使用自動ZMQ_IDENTITY.
ZMQ_IDENTITY就是socket的名字。
Gtw向Gs發(fā)送消息時,須先指定對方的名字,然后才能發(fā)送到指定的Gs.
接收時,也會附帶獲取對方的名字。
Gtw是自動ZMQ_IDENTITY,每次連接Gs, Gs就會自動為其設定一個隨機的名字。
Gtw重啟后,希望其名字與前次運行的名字不相同,所以設為自動ZMQ_IDENTITY.
Gs端只需一次bind:
zmq::socket_t sktGs(context, ZMQ_ROUTER);
sktGs.setsockopt(ZMQ_IDENTITY, ...);
sktGs.bind("tcp://*:12345");
Gtw端須連接多個Gs, Gs的IP和端口是配置的:
zmq::socket_t sktGtw(context, ZMQ_ROUTER);
BOOST_FOREACH(int nGsId, setGsIds);
{
sktGtw.connect(Fmt("tcp://%s:%u",
config.GetGsHost(nGsId),
config.GetGsPort(nGsId)));
}
Gtw重啟后,應該假設此時Gs可能尚未存在,須不斷向Gs發(fā)Init消息。
Gs應答InitAck之后就可以確認與Gs之間的連接建立成功。
Gs的名字是從配置文件讀取的。
Gs重啟后,將等待Gtw的消息,如果是Init, 則應答InitAck.
如果是其他消息,則發(fā)送Reset, 讓Gtw重置。
Gtw接到Reset后,將發(fā)送Init, 并等待InitAck.
如此,Gs與Gtw將不存在啟動順序關系,并且服務器可任意重啟而不影響其他服務器。
(金慶的專欄)
Zeromq無需bind, connect次序,可以在對方bind之前就connect, 可實現(xiàn)服務器以任意順序啟動。
Zmq有自動重連功能,可實現(xiàn)服務器故障重啟不影響整個系統(tǒng)。
萬神服務器內部連接采用了Zmq, 并可能在未來將客戶端服務器之間的連接也改用為Zmq。
萬神的網(wǎng)關(Gtw,Gateway)與游戲服(Gs, Game Server)之間是M*N的全互連關系。
即M個網(wǎng)關,N個游戲服,每個Gtw連接所有Gs, 每個Gs連接所有Gtw.
采用Zmq的Router-Router模式,Gtw和Gs分別只需一個zmq::socket_t, 就可以實現(xiàn)M*N互連。
Router-Router互連的決竅是至少其中一方須設置ZMQ_IDENTITY.
因為Gs是穩(wěn)定的服務器,數(shù)量固定,所以設為bind方,并設置 ZMQ_IDENTITY.
Gtw是可任意添加的服務器,所以設為connect方,使用自動ZMQ_IDENTITY.
ZMQ_IDENTITY就是socket的名字。
Gtw向Gs發(fā)送消息時,須先指定對方的名字,然后才能發(fā)送到指定的Gs.
接收時,也會附帶獲取對方的名字。
Gtw是自動ZMQ_IDENTITY,每次連接Gs, Gs就會自動為其設定一個隨機的名字。
Gtw重啟后,希望其名字與前次運行的名字不相同,所以設為自動ZMQ_IDENTITY.
Gs端只需一次bind:
zmq::socket_t sktGs(context, ZMQ_ROUTER);
sktGs.setsockopt(ZMQ_IDENTITY, ...);
sktGs.bind("tcp://*:12345");
Gtw端須連接多個Gs, Gs的IP和端口是配置的:
zmq::socket_t sktGtw(context, ZMQ_ROUTER);
BOOST_FOREACH(int nGsId, setGsIds);
{
sktGtw.connect(Fmt("tcp://%s:%u",
config.GetGsHost(nGsId),
config.GetGsPort(nGsId)));
}
Gtw重啟后,應該假設此時Gs可能尚未存在,須不斷向Gs發(fā)Init消息。
Gs應答InitAck之后就可以確認與Gs之間的連接建立成功。
Gs的名字是從配置文件讀取的。
Gs重啟后,將等待Gtw的消息,如果是Init, 則應答InitAck.
如果是其他消息,則發(fā)送Reset, 讓Gtw重置。
Gtw接到Reset后,將發(fā)送Init, 并等待InitAck.
如此,Gs與Gtw將不存在啟動順序關系,并且服務器可任意重啟而不影響其他服務器。