行業資訊

  • 首頁
  • 新聞中心
  • 行業資訊

手游服務端框架之跨服匹配服,手游服務器租用


2018年08月29日

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

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

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

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

下面,開始我們的編碼。

★如有手游服務器租用可咨詢宇眾臨風,QQ:2850293179   Tel:15999932452   訂購網址:www.jindaxi.cn

搭建mina的http服務

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


 
  1. /**

  2. * 匹配服http服務

  3. * @author kingston

  4. */

  5. public class MatchServer {

  6.  
  7. private Logger logger = LoggerFactory.getLogger(MatchServer.class);

  8.  
  9. private IoAcceptor acceptor;

  10.  
  11. //http端口

  12. int port = 8899;

  13.  
  14. public void start() throws Exception {

  15. acceptor = new NioSocketAcceptor();

  16. acceptor.getFilterChain().addLast("codec", new HttpServerCodec());

  17. acceptor.setHandler(new HttpServerHandle());

  18.  
  19. acceptor.bind(new InetSocketAddress(port));

  20.  
  21. logger.error("---------> http server start at port:{}", port);

  22. }

  23.  
  24. public void shutdown() {

  25. if (acceptor != null) {

  26. acceptor.unbind();

  27. acceptor.dispose();

  28. }

  29. logger.error("---------> http server stop at port:{}", port);

  30. }

  31. }

  32.  
  33. class HttpServerHandle extends IoHandlerAdapter {

  34.  
  35. private static Logger logger = LoggerFactory.getLogger(MatchServer.class);

  36.  
  37. @Override

  38. public void exceptionCaught(IoSession session, Throwable cause)

  39. throws Exception {

  40. }

  41.  
  42. @Override

  43. public void messageReceived(IoSession session, Object urlParams)

  44. throws Exception {

  45. if (urlParams instanceof HttpRequest) {

  46. // 請求,解碼器將請求轉換成HttpRequest對象

  47. HttpRequest request = (HttpRequest) urlParams;

  48. Message msg = parseHttpRequest(request);

  49. UrlDispatcher.getInstance().dispatch(session, msg);

  50. }

  51. }

  52.  
  53. @SuppressWarnings("unchecked")

  54. private Message parseHttpRequest(HttpRequest httpReq) {

  55. String service = httpReq.getParameter("service");

  56. if (StringUtils.isEmpty(service)) {

  57. return null;

  58. }

  59.  
  60. Class<?> clazz = UrlDispatcher.getInstance().getMessageClazzBy(service);

  61. String paramJson = httpReq.getParameter("param");

  62. if (StringUtils.isNotEmpty(paramJson)) {

  63. try{

  64. return (Message)new Gson().fromJson(URLDecoder.decode(paramJson), clazz);

  65. }catch(Exception e) {

  66. e.printStackTrace();

  67. }

  68. }

  69. return null;

  70. }

  71.  
  72. }

消息通信

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

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

為了能區別游戲服和匹配服的消息類型,我們匹配服的消息,都加一個M(Match)前綴,那么請求協議就MReq,響應協議就是MRes了。

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


 
  1. public class MatchHttpUtil {

  2.  
  3. public static Message submit(Message request) throws IOException {

  4. String signature = request.getClass().getSimpleName();

  5. String data = new Gson().toJson(request);

  6. String param = HttpUtil.buildUrlParam("service", signature,

  7. "param", data);

  8.  
  9. String url = "http://localhost:8899" + "?" + param;

  10. System.err.println("發送url:" + url);

  11. String resultJson = HttpUtil.get(url);

  12. UrlResponse urlResponse = new Gson().fromJson(resultJson, UrlResponse.class);

  13.  
  14. String respClazz = urlResponse.getAttachemt();

  15. Class<?> msgClazz = MatchMessageFactory.getInstance().getMessageBy(respClazz);

  16. Message msgResponse = (Message)new Gson().fromJson(urlResponse.getMessage(), msgClazz);

  17. return msgResponse;

  18. }

  19.  
  20. }

 

業務處理器

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

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


 
  1. public class UrlDispatcher {

  2.  
  3. private Logger logger = LoggerFactory.getLogger(getClass());

  4.  
  5. private volatile static UrlDispatcher instance;

  6.  
  7. /** [message signature, CmdExecutor] */

  8. private static final Map<String, CmdExecutor> service2Handler = new HashMap<>();

  9.  
  10. private static final Map<String, Class<?>> signature2Message = new HashMap<>();

  11. }

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


 
  1. public void dispatch(IoSession session, Message message) {

  2. String signature = buildSignature(message.getClass());

  3. CmdExecutor cmdExecutor = service2Handler.get(signature);

  4. if (cmdExecutor == null) {

  5. logger.error("message executor missed, signature={}", signature);

  6. return;

  7. }

  8.  
  9. Object[] params = convertToMethodParams(session, cmdExecutor.getParams(), message);

  10. Object controller = cmdExecutor.getHandler();

  11. try {

  12. //通過反射

  13. cmdExecutor.getMethod().invoke(controller, params);

  14. }catch(Exception e) {

  15. logger.error("", e);

  16. }

  17. }

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


 
  1. @Controller

  2. public class LadderController {

  3.  
  4. @RequestMapping

  5. public void apply(IoSession session, MReqLadderApplyMessage request) {

  6. HttpMessagePusher.push(session, new MResLadderApplySuccMessage());

  7. }

  8.  
  9. }

示例代碼

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

再執行游戲服的單元測試


 
  1. public class TestMatchHttp {

  2.  
  3. @Test

  4. public void httpRquest() throws IOException {

  5. Message response = MatchHttpUtil.submit(new MReqLadderApplyMessage());

  6.  
  7. System.err.println("收到響應<<<<<<<<<" + response);

  8. }

  9. }

 

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


客服
主站蜘蛛池模板: 欧美自拍另类欧美综合图片区| 狠狠色丁香久久婷婷综合| 亚洲综合区小说区激情区| 久久综合色之久久综合| 狠狠色噜噜狠狠狠狠色综合久| 亚洲av综合av一区| 亚洲狠狠久久综合一区77777| 国产亚洲综合成人91精品| 伊色综合久久之综合久久| 久久久久久久综合日本亚洲| 丁香五月婷婷综合激情在线| 欧美一区二区三区久久综合| 亚洲国产综合网| 亚洲 欧洲 日韩 综合在线| 欧美日韩国产综合视频在线观看| 亚洲 欧洲 日韩 综合在线| 狠狠色丁香久久婷婷综合图片| 国产综合内射日韩久| 色综合久久88色综合天天 | 国产成人精品综合网站| 狠狠色综合网站久久久久久久高清| 亚洲综合伊人久久大杳蕉| 国产成人综合久久精品红| 五月天激情综合| 天天综合网天天综合色| 99久久婷婷国产综合精品草原| 久久―日本道色综合久久| 久久精品国产91久久综合麻豆自制| 一个色综合久久| 国产欧美日韩综合精品一区二区三区| 色天使久久综合网天天| 婷婷五月综合色视频| 东京热TOKYO综合久久精品| 伊人久久大香线焦综合四虎| 亚洲国产婷婷综合在线精品| 久久综合成人网| 国产天天综合永久精品日| 色综合欧美在线视频区| 色综合网站国产麻豆| 国产综合亚洲专区在线| 2020国产精品亚洲综合网|