Learn Mina purpose or build communication architecture, learn Mina we know how to implement the client and the service side, that is, a normal channel we know how to build
But the problem is that we use environmental communication in two ways
1. Front-end communication
In fact, this is a better implementation, provide a Mina server side, for the front-end language through the socket to connect the line, this communication even if it is OK, codec and other communication analysis of the details here do not say
The previous game server architecture business with short connections, chat with a long connection, the part of the chat is actually the above stated situation
Now is the long connection of the world, chat is still a long connection, the business also make a growth connection, realize the true meaning of the long-connected game architecture, which actually expressed a typical structure of the present,
Is the backend provides two open communication ports "two Mina server" for the front-end socket connection, one responsible for chat, login, registration, and another responsible for other business, so that the protocol to achieve load balancing communication
2. Back-end business service communication "This is the focus of this article"
So does the backend business need no load balancing? such as job, asynchronous update db, active copy, etc.
Of course it is necessary, how to do that, first of all, take 1 to make an explanation
mainserevr[Chat, login, register]---nodeserver[other business]
These two Mina sever have been established, but the two servers are not able to communicate, we have two choices, or a Mina client on MAINSEREVR to connect Nodeserver, or Nodeserver
On a Mina client to even MAINSEREVR, the idea is certainly such, once this channel was established, in fact, each other for the server and the client, there will be a iosession by the channel holding, as long as there is this iosession,
Can be active write, of course, the other end of the channel can be response, can also be obtained by iosession to actively write
Implementation, we provide a mainserverclient such a spring bean on the NODESEREVR to connect Mainserver so that the nodeserver can send messages to MAINSEREVR
3. Design with this idea
I divide the business in the game into
public static final String server_type_node_str = "Nodeserver";//game nodepublic static final string server_type_main_str = "Mainserver";//main serverpublic static final String server_type_job_str = "JobServer";//JOB serverpublic static final St Ring SERVER_TYPE_ASYNCDB_STR = "Asyncdbserver";//Async dbpublic static final String server_type_active_str = " Activityserver ";//Active public static final String server_type_other_str =" other ";//other public static final string Server_typ E_gm_str = "GM";//Management side
Each time you start a server, start Mina SEREVR first, and then start multiple Mina clients to connect to the other Mina server.
For example, start the NODESEREVR server, and then start multiple clients to connect to the MAINSEREVR,JOBSEREVR, etc., so that I can
On Nodeserver to other business SEREVR request, specifically launched which client see need
Get a way to start the server type
public static Classpathxmlapplicationcontext Start (String servertypestr) {try {
Close the hook thread of the connection pool Proxoolfacade.disableshutdownhook ();
Spring's core configuration file is string xmlfile = "Applicationcontext.xml"; Log.info ("Start {} server ... ......... );//set to System environment variable System.setproperty (nodesessionmgr.server_type_key, ServerType + ""); System.setproperty (nodesessionmgr.server_type_name_key,servertypename);//Final Classpathxmlapplicationcontext Parent = new//Classpathxmlapplicationcontext (//XMLFile); String fileName = null;
This is to split the spring live configuration file part of the content, is currently only load the SERVER needs beanif (ServerType = = Nodesessionmgr.server_type_node) {fileName = "wolf /app_nodeserver.xml ";} else {fileName = "wolf/app_server.xml";}//Manual start springfinal classpathxmlapplicationcontext context = new Classpathxmlapplicationcontext (new string[] { XMLFile, fileName});if (context! = null) {servicelocator.getinstance (). Setapplicationcontext (context);} Start socket serverfinal wolfserver server = (wolfserver) servicelocator.getspringbean ("Wolf_server"); Server.setservertype (ServerType);
This call is what we are familiar with starting the Mina server sideServer.start ();This is done for two things, the SEREVR type that the constituency needs to establish Mina client connectionstartclient (server);
The hook thread is used to listen for the application to stop, in order to do the subsequent processing of the Stop Runtime.getruntime (). Addshutdownhook (New Thread (new Runnable () {public void Run () {_ Shutdown ();}}, "Shutdownhookthread");
To support WEB,SPRINGMVC, a built-in web Serverif (NodeSessionMgr.SERVER_TYPE_MAIN_STR.equalsIgnoreCase (servertypestr)) { Jettyserver jettyserver = (jettyserver) servicelocator.getspringbean ("Jettyserver"); Jettyserver.start ();} Log.info ("Start {} end ....................... servertypename); return context;} catch (Exception e) {e.printstacktrace (); Shutdown ();} finally {}return null;}
Looking at the startclient (server);
private static void Startclient (Wolfserver server) {//Asyncdbserver will only be connected and will not be actively connected to other servers
//The purpose of this is to filter out the SEREVR that do not require active continued proportion, and to contest my asynchronous db, and the activeif (server.getservertype () = = nodesessionmgr.server_type_asyncdb| | server.getservertype () = = NodeSessionMgr.SERVER_ type_active) {return;} Send the game Server IP port to mainservermap<string, object> params = new hashmap<string, object> ();p arams.put (" Nodeserverip ", Server.getip ());p arams.put (" Nodeserverport ", Server.getport ());p arams.put (" ServerType ", Server.getservertype ());//I need MAINSEREVR client, get a bean in this service final iwolfclientservice mainserverclient = (iwolfclientservice) Servicelocator.getspringbean ("Mainserverclient");//This location is actually Mina's client server sidemainserverclient.init ();Object localaddress = Mainserverclient.registernode (params);
///Ibid., Requires JOBSEREVR clientFinal Iwolfclientservice jobserverclient = (iwolfclientservice) servicelocator.getspringbean ("JobServerClient"); Jobserverclient! = null) {jobserverclient.init ();map<string, object> params1 = new hashmap<string, object> ();p arams1.putall (params); Jobserverclient.registernode (PARAMS1);} // }.....}
Take a look at the Wolfclientservice.init ()
public void init () {if (start) return;if (wolfclient = = null) {Log.error ("Wolf client is null"); return;} Mina Client connection Mina serverwolfclient.start (); if (wolfclient.isconnected ()) start = true;}
Take a look at the Wolfclient.start ()
/** * Connect a server and specify the processing method for processing received messages * */public void start () {//This.context.put ("Resultmgr", this.resultmgr); Logger.info ( Com.youxigu.dynasty2.i18n.MarkupMessages.getString ("Wolfclient_9"), Processornum); Logger.info ( Com.youxigu.dynasty2.i18n.MarkupMessages.getString ("Wolfclient_0"), corepoolsize); Logger.info ( Com.youxigu.dynasty2.i18n.MarkupMessages.getString ("Wolfclient_4"), maxpoolsize); if (This.serverip = = NULL | | This.serverIp.equals (")) {Logger.error (" ") {clientName +" no ServerIP configured, no start ... "); return;} String Threadprefix = ClientName + "[" + This.serverip + ":" + This.serverport + "]";//Exector = Executors.newcachedthread Pool (new//namingthreadfactory (threadprefix));p rocessor = new Simpleioprocessorpool<niosession> ( Nioprocessor.class,processornum);//connector = new Niosocketconnector ((Executor) exector, processor); connector = new Niosocketconnector (processor);//Connector.getsessionconfig (). Setreuseaddress (True);D Efaultiofilterchainbuilder Chain = Connector.getfilterchain (); if (USelogfilter = = 2) {chain.addlast ("Logging", New Loggingfilter ());} Codec filter to be placed before executorfilter, because read and write the same socket connection socket//BUF can not be concurrent (in fact, mainly read, the write operation Mina has been encapsulated into a write Queue) Chain.addlast ("Codec", new Protocolcodecfilter (codecfactory)); Set the encoding filter//Add a heartbeat filter, the client only accepts heartbeat requests from the server, does not send heartbeat requests//Connector.getsessionconfig (). Setreaderidletime (readidletimeout);// The keepalivefilter here must be after codec, because Keepalivemessagefactoryimpl returns an object if Keepalivemessagefactoryimpl returns Iobuffer Before codec//Keepalivefilter in the end before Executorfilter good or after, I'm not sure keepalivefilter filter = new Keepalivefilter (new Keepalivemessagefactoryimpl (keepaliverequestinterval <= 0), Idlestatus.reader_idle, new Requesttimeoutclosehandler (), Keepaliverequestinterval <= 0? 600:keepaliverequestinterval,30); Chain.addlast ("Ping", filter);//Add execution thread Pool executor = new Unorderedthreadpoolexecutor (Corepoolsize, Maxpoolsize,keepalivetime, Timeunit.seconds, New Namingthreadfactory (Threadprefix));// Here is a pre-boot corepoolsize processing thread executor.prestartallcorethreads(); Chain.addlast ("Exec", new Executorfilter (Executor,ioeventtype.exception_caught, ioeventtype.message_received, ioeventtype.session_closed, ioeventtype.session_idle,ioeventtype.session_opened)); if (UseWriteThreadPool) { Executorwrite = new Unorderedthreadpoolexecutor (corepoolsize,maxpoolsize, KeepAliveTime, TimeUnit.SECONDS,new Namingthreadfactory (Threadprefix + "write"); Executorwrite.prestartallcorethreads (); Chain.addlast ("ExecWrite", New Executorfilter (Executorwrite,ioeventtype.write, ioeventtype.message_sent));} , logger.isdebugenabled ()? new//Loggingioeventqueuehandler ("Execwrite"): nulls//Configuration Handler logger, after codec, printed decode before or after encode messages log// Can be configured after Executorfilter: is to print the log in the worker thread, not to print if (Uselogfilter = = 1) {Chain.addlast ("logging") in Nioprocessor, new Loggingfilter ());} Connector.sethandler (handler); Connector.getsessionconfig (). Setreuseaddress (True); Connector.getsessionconfig (). Settcpnodelay (Tcpnodelay); Logger.info (com.youxigu.dynasty2.i18n.MarkupMessages.getString ("Wolfclient_1 ") + ServerIP +": "+ serverport); Connectfuture CF = Null;long start = System.currenttimemillis ();While (true) { //The ground is critical, is a wireless loop that is connected every 10 seconds until a connection can be established with the server, or a loop goes down CF = Connector.connect (ser veraddress);//Establish Connection cf.awaituninterruptibly (10000L); if (!cf.isconnected ()) {if (System.currenttimemillis ()-start) > Timeout) {throw new RuntimeException (com.youxigu.dynasty2.i18n.MarkupMessages.getString ("wolfclient_5") + ServerIP + ":" + ServerPort);} if (cf.getexception () = null) {Logger.error (com.youxigu.dynasty2.i18n.MarkupMessages.getString ("Wolfclient_6"), ServerIP + ":" + ServerPort, Cf.getexception (). GetMessage ());} try {thread.sleep (10000);} catch (Exception e) {}continue;}
//This is the ultimate goal, and our goal is to get this iosessionthis.setsession (Cf.getsession ()) in the bean of the SEREVR client;Logger.info (com.youxigu.dynasty2.i18n.MarkupMessages.getString ("wolfclient_10") + ServerIP + ":" + serverport); ShutDown = false;if (Handler instanceof Wolfmessagechain) {Wolfmessagechain WMC = WolfMessageChain.class.cast (handler); Wmc.init (context);} Break;}}
So the back end of the business communication network can be easily built up, and then how to communicate to see your
"MINA" uses MINA to do the communication between business suits, realizes the business load balance idea