網遊伺服器常部署網關服務,作為客戶端與內部叢集的通訊代理:將客戶端訊息分發至正確的內部伺服器,並將內部回應轉發給客戶端。廣播服務是網關最大的壓力來源——單一玩家的行為可能需廣播給數百名可見玩家。本文示範用 kendynet 實作簡易網關,僅做訊息轉發演示,實際生產環境會更複雜。
static msgdisp_t disp_to_server; static msgdisp_t disp_to_client; sock_ident to_server;
定義兩個訊息處理器:disp_to_client 處理來自客戶端的訊息,disp_to_server 處理來自內部伺服器的訊息;to_server 代表與內部伺服器的連線識別碼。
asynnet_t asynet = asynnet_new(3); // 3 poller:監聽、客戶端、伺服器 msgdisp_t disp_to_server = new_msgdisp(asynet, to_server_connect, to_server_connected, NULL, to_server_process, NULL); msgdisp_t disp_to_client = new_msgdisp(asynet, to_client_connect, NULL, NULL, to_client_process, NULL); thread_t service1 = create_thread(THREAD_JOINABLE); thread_t service2 = create_thread(THREAD_JOINABLE); // ... 設定 IP/port ... thread_start_run(service1, service_toserver, (void*)disp_to_server); sleepms(1000); thread_start_run(service2, service_toclient, (void*)disp_to_client);
建立非同步網路引擎(3 個 poller),分別綁定不同連線類型的回呼,最後啟動兩條執行緒並行處理。
void to_server_connected(msgdisp_t disp, sock_ident sock, const char *ip, int32_t port, uint32_t err) {
to_server = sock;
}
int32_t to_client_process(msgdisp_t disp, sock_ident sock, rpacket_t rpk) {
if (!eq_sockident(sock, to_server)) {
push_msg(disp_to_server, (msg_t)rpk); // 客戶端→伺服器
} else {
sock_ident client = read_from_rpacket(rpk);
asyn_send(client, wpk_create_by_other((struct packet*)rpk)); // 伺服器→客戶端
}
return 1;
}
void to_client_connect(msgdisp_t disp, sock_ident sock, const char *ip, int32_t port) {
disp->bind(disp, 3, sock, 1, 3*1000, 0); // 綁定第 3 poller
}
int32_t to_server_process(msgdisp_t disp, sock_ident sock, rpacket_t rpk) {
if (!eq_sockident(sock, to_server)) {
asyn_send(to_server, wpk_create_by_other((struct packet*)rpk)); // 客戶端→伺服器
} else {
push_msg(disp_to_client, (msg_t)rpk); // 伺服器→客戶端
}
return 1;
}
void to_server_connect(msgdisp_t disp, sock_ident sock, const char *ip, int32_t port) {
disp->bind(disp, 2, sock, 1, 3*1000, 0); // 綁定第 2 poller
}
連線建立時綁定對應 poller;處理函式根據來源套接字決定轉發方向,實現雙向透傳。
完整範例參考:GitHub 原始碼
作者:玄魂
出處:https://www.cnblogs.com/xuanhun/