手遊服務端架構之跨服匹配服__架構

來源:互聯網
上載者:User

如今的手遊世界,如果沒搞個跨服賽事,都不好意思說它是一個手遊了。

說到跨服,就不得不說下匹配服了。比如一個跨服天梯賽事,需要滿足不同服的玩家能夠同屏PK。為了能夠把實力接近的玩家作為對手,我們需要一個獨立的匹配服來收集資料,然後進行房間分配。匹配服,也是跨服賽設計的基礎。

典型的匹配服通訊層我們可以採用http,也可以採用socket。本文將採用http作為遊戲服與匹配服的通訊層。選擇http方式,我們可以搭個tomcat服務,非常方便。當然,如果不使用tomcat的話,我們也可以使用mina或者netty本身的http服務。

設計思路也非常簡單,有點像遊戲服的業務處理器。我們需要做到,對於不同的請求,我們都綁定一個方法與之對應。而對於資料的編解碼,由於匹配服的通訊資料一般都比較短,我們直接用json進行序列化即可。

下面,開始我們的編碼。 搭建mina的http服務

在前面遊戲後台設計中,我們已經看到如何使用mina搭建http服務了。

/** * 匹配服http服務 * @author kingston */public class MatchServer {private Logger logger = LoggerFactory.getLogger(MatchServer.class);private IoAcceptor acceptor;//http連接埠int port = 8899;public void start() throws Exception {acceptor = new NioSocketAcceptor();acceptor.getFilterChain().addLast("codec", new HttpServerCodec());acceptor.setHandler(new HttpServerHandle());acceptor.bind(new InetSocketAddress(port));logger.error("---------> http server start at port:{}", port);}public void shutdown() {if (acceptor != null) {acceptor.unbind();acceptor.dispose();}logger.error("---------> http server stop at port:{}", port);}}class HttpServerHandle extends IoHandlerAdapter {private static Logger logger = LoggerFactory.getLogger(MatchServer.class);@Overridepublic void exceptionCaught(IoSession session, Throwable cause)throws Exception {}@Overridepublic void messageReceived(IoSession session, Object urlParams)throws Exception {if (urlParams instanceof HttpRequest) {// 請求,解碼器將請求轉換成HttpRequest對象HttpRequest request = (HttpRequest) urlParams;Message msg = parseHttpRequest(request);UrlDispatcher.getInstance().dispatch(session, msg);}}@SuppressWarnings("unchecked")private Message parseHttpRequest(HttpRequest httpReq) {String service = httpReq.getParameter("service");if (StringUtils.isEmpty(service)) {return null;}Class<?> clazz = UrlDispatcher.getInstance().getMessageClazzBy(service);String paramJson = httpReq.getParameter("param");if (StringUtils.isNotEmpty(paramJson)) {try{return (Message)new Gson().fromJson(URLDecoder.decode(paramJson), clazz);}catch(Exception e) {e.printStackTrace();}}return null;}}
訊息通訊

在遊戲服,我們發出一條http請求。匹配服為了將請求分發到對應的處理器,我們需要為每一條訊息作一個標記。最簡單的,可以使用請求訊息的類名。所以,我們必須把業務簽名和參數都融合到url裡面去。也就是說,一個有效url可能是這樣:

http://localhost:8899?service=MReqLadderApplyMessage&param={"playerId":0,"score":0,"power":0}

為了能區別遊戲服和匹配服的訊息類型,我們匹配服的訊息,都加一個M(Match)首碼,那麼請求協議就MReq,響應協議就是MRes了。

對於遊戲服來說,發出的請求屬於Message的子類,返回的訊息也是Message的子類。底層幫我們實現了訊息的編解碼。我們可以看下代碼實現。

public class MatchHttpUtil {public static Message submit(Message request) throws IOException {String signature = request.getClass().getSimpleName();String data = new Gson().toJson(request);String param = HttpUtil.buildUrlParam("service", signature,"param", data);String url = "http://localhost:8899" + "?" + param;System.err.println("發送url:" + url);String resultJson = HttpUtil.get(url);UrlResponse urlResponse = new Gson().fromJson(resultJson, UrlResponse.class);String respClazz = urlResponse.getAttachemt();Class<?> msgClazz = MatchMessageFactory.getInstance().getMessageBy(respClazz);Message msgResponse = (Message)new Gson().fromJson(urlResponse.getMessage(), msgClazz);return msgResponse;}}

業務處理器

我們依然使用 @Controller註解來標識一個模組處理器,使用@RequestMapper註解來標記業務處理方法。不同的是,在遊戲服我們每個訊息的元資訊都帶有一個模組號和子類型號。在匹配服,我們就不這裡處理了。因為匹配服的業務比較少。我們直接用訊息類的名稱作為業務簽名即可。

在業務分發器,我們儲存每一個方法簽名,與對應的方法處理器。

public class UrlDispatcher {private Logger logger = LoggerFactory.getLogger(getClass());private volatile static UrlDispatcher instance;/** [message signature, CmdExecutor] */private static final Map<String, CmdExecutor> service2Handler = new HashMap<>();private static final Map<String, Class<?>> signature2Message = new HashMap<>();}

匹配服在收到一個http請求,通過參數解析得到對應的業務簽名,同時通過json還原序列化得到請求訊息的參數。將訊息分發到對應的業務處理器。代碼如下: 

public void dispatch(IoSession session, Message message) {String signature = buildSignature(message.getClass());CmdExecutor cmdExecutor = service2Handler.get(signature);if (cmdExecutor == null) {logger.error("message executor missed, signature={}", signature);return;}Object[] params = convertToMethodParams(session, cmdExecutor.getParams(), message);Object controller = cmdExecutor.getHandler();try {//通過反射cmdExecutor.getMethod().invoke(controller, params);}catch(Exception e) {logger.error("", e);}}

一個完整的業務處理器,代碼如下 (可以看出,跟遊戲服是非常類似的):

@Controllerpublic class LadderController {@RequestMappingpublic void apply(IoSession session, MReqLadderApplyMessage request) {HttpMessagePusher.push(session, new MResLadderApplySuccMessage());}}
範例程式碼

啟動匹配服伺服器(MatchStartup.java)

再執行遊戲服的單元測試

public class TestMatchHttp {@Testpublic void httpRquest() throws IOException {Message response = MatchHttpUtil.submit(new MReqLadderApplyMessage());System.err.println("收到響應<<<<<<<<<" + response);}}


手遊服務端開源架構系列完整的代碼請移步github ->> jforgame

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.