Today's hand tour the world, if not a cross-service tournament, are embarrassed to say it is a hand swim.
When it comes to cross clothing, you have to say the matching suit. For example, a cross-service ladder race, the need to meet different clothing players can be the same screen PK. In order to be able to match the players who are close to each other, we need a separate matching suit to collect the data and then make room allocations. Matching suits, is also the basis of the design of the cross-service.
Typical matching service communication layer we can use HTTP, also can use socket. In this paper, HTTP is used as the communication layer of game suit and matching suit. Choose the HTTP method, we can take a Tomcat service, very convenient. Of course, if you don't use Tomcat, we can also use the HTTP services of Mina or Netty itself.
The design idea is also very simple, a bit like the business processor of the game suit. We need to do that, for different requests, we all bind a method to correspond to it. And for the data codec, because the matching service communication data are generally relatively short, we directly use JSON serialization can be.
Below, start our code. build Mina's HTTP service
In front of the game background design, we have seen how to use Mina to build the HTTP service.
/** * Matching HTTP service * @author Kingston */public class Matchserver {private Logger Logger = Loggerfactory.getlogger (MATC
Hserver.class);
Private Ioacceptor acceptor;
HTTP port 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 (matchserve
R.class); @Override public void Exceptioncaught (iosession sessions, Throwable cause) throws Exception {} @Override public Vo ID Messagereceived (iosession session, Object Urlparams) throWS Exception {if (urlparams instanceof HttpRequest) {//request, decoder converts requests to HttpRequest object HttpRequest request = (httpre
Quest) 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), CLA
ZZ);
}catch (Exception e) {e.printstacktrace ();
} return null; }
}
Message Communication
In the game costume, we issue an HTTP request. Matching suit in order to distribute the request to the corresponding processor, we need to mark each message. Most simply, you can use the class name of the request message. Therefore, we must integrate the business signature and parameters into the URL. In other words, a valid URL might be this:
http://localhost:8899?service=mreqladderapplymessage¶m={"playerID": 0, "score": 0, "Power": 0}
In order to distinguish between the game suit and the matching service message type, we match the service message, all add a m (match) prefix, then the request protocol is MREQ, the response agreement is MREs.
For a game suit, the request is a subclass of the message, and the returned messages are also subclasses of the information. The bottom of the story helps us to decode the message. We can look at the code implementation.
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 ("Send 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
}
}
Business Processors
We still use @Controller annotations to identify a module processor and use @requestmapper annotations to mark the business processing method. The difference is that the meta information for each message in the game costume comes with a module number and a subclass model. In matching suits, we're not dealing with here anymore. Because the business of matching suits is relatively small. We directly use the name of the message class as the business signature.
In the business distributor, we save each method signature, with the corresponding method processor.
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 Hash Map<> ();
Private static final map<string, class<?>> signature2message = new hashmap<> ();
}
The matching suit receives an HTTP request, the corresponding business signature is obtained by parameter parsing, and the parameters of the request message are deserialized by JSON. Distribute messages to the corresponding business processor. The code is as follows:
public void dispatch (Iosession sessions, message message) {
String signature = buildsignature (Message.getclass ()); C1/>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 {
//through Reflection
Cmdexecutor.getmethod (). Invoke (Controller, params);
catch (Exception e) {
logger.error ("", e);
}
}
A complete business processor, the code is as follows (as you can see, it's very similar to a game suit):
@Controller public
class Laddercontroller {
@RequestMapping
the public void apply (Iosession session, Mreqladderapplymessage request) {
Httpmessagepusher.push (session, New Mresladderapplysuccmessage ());
}
Sample Code
Start a matching service server (Matchstartup.java)
To perform the unit test of the game suit again
public class Testmatchhttp {
@Test public
void Httprquest () throws IOException {message
response = Matchhttp Util.submit (New Mreqladderapplymessage ());
SYSTEM.ERR.PRINTLN ("Received response <<<<<<<<<" + response);
}
Hand Tour Service End Open source Framework series complete code please go to GitHub->> Jforgame