亚洲午夜无码久久,今天高清视频免费观看,欧美一夜爽爽爽爽爽爽,在线亚洲欧美日韩精品专区

行業(yè)資訊

  • 首頁
  • 新聞中心
  • 行業(yè)資訊

手游服務(wù)端框架之跨服匹配服,手游服務(wù)器租用


2018年08月29日

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

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

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

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

下面,開始我們的編碼。

★如有手游服務(wù)器租用可咨詢宇眾臨風,QQ:2850293179   Tel:15999932452   訂購網(wǎng)址:www.yelaoxs.com

搭建mina的http服務(wù)

在前面游戲后臺設(shè)計中,我們已經(jīng)看到如何使用mina搭建http服務(wù)了。


 
  1. /**

  2. * 匹配服http服務(wù)

  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. // 請求,解碼器將請求轉(zhuǎn)換成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. }

消息通信

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

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

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

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


 
  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("發(fā)送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. }

 

業(yè)務(wù)處理器

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

在業(yè)務(wù)分發(fā)器,我們保存每一個方法簽名,與對應(yīng)的方法處理器。


 
  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請求,通過參數(shù)解析得到對應(yīng)的業(yè)務(wù)簽名,同時通過json反序列化得到請求消息的參數(shù)。將消息分發(fā)到對應(yīng)的業(yè)務(wù)處理器。代碼如下: 


 
  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. }

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


 
  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. }

示例代碼

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

再執(zhí)行游戲服的單元測試


 
  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("收到響應(yīng)<<<<<<<<<" + response);

  8. }

  9. }

 

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


客服