Project Address Https://git.oschina.net/rushmore/zbus
Last time we talked about the core API of Zbus network communication :
Dispatcher -- responsible for -nio Network event Selector engine management, load Balancing for Selector engine
Ioadaptor- Network event processing, server and client sharing, responsible for reading and writing, message subcontracting packets, etc.
Session-- represents the network link, can read and write messages
Practical applications, we almost only need to do ioadaptor Personalized implementation to complete the efficient network communication services, today we will illustrate how to personalize the ioadaptor.
The goals we are going to accomplish today are: implementing A transparent proxy for the MySQL server . The effect is that you access the proxy server with no differences in access to the target MySQL .
we're in the test environment 10.17.2.30 : 3306 This machine provides MySql, running on our local machine we are today based on Zbus . NET implementation of an agent, you can achieve the following effect.
less than 1 complete xx line of code , Cool? let' sroll!
First, we consider what the transparent TCP agent is doing, the transparent TCP agent's business logic is actually very simple, can be described as, from the upstream of the agent (initiating the request to the agent) the data forwarded to the target The TCP server returns the destination server back to the proxy upstream client for the original path. Note that the original path, how to do the original return to become the key point. This example does not actually have anything to do with MySQL, in principle any TCP level service should be appropriate.
based on Zbus . NETioadaptor 1 A link request originated from an upstream client -- proxy server accept events, 2 ) proxy server connection to target server connect event, 3 ) upstream and downstream data events
zbus.net the individual events provided by Ioadaptor are as follows
The basic includes a link (client or server) life cycle, and the codec of the message.
our Agents Ioadaptor is individually handled individually.
The first step , Codec: Transparent agents do not understand the content of the message, so do not need to encode and decode.
Pass-through does not need to be decoded, simple return bytebuffer data public iobuffer encode (Object msg) {if (msg instanceof iobuffer) {Iobuffer buff = (iobuffer) m Sg;return Buff;} else {throw new RuntimeException ("Message not support");}} Pass-through does not need to be decoded, simple return bytebuffer data public Object decode (Iobuffer buff) {if (buff.remaining () > 0) {byte[] data = new Byte[buff . Remaining ()];buff.readbytes (data); return iobuffer.wrap (data);} else {return null;}}
Step Two , Proxy service access:
@Overrideprotected void onsessionaccepted (Session sess) throws IOException {session target = Null;dispatcher Dispatcher = Sess.getdispatcher (); try {target = Dispatcher.createclientsession (targetAddress, this);} catch (Exception e) { Sess.asyncclose (); return;} Sess.chain = Target;target.chain = Sess;dispatcher.registersession (Selectionkey.op_connect, target);}
The logical idea here is that the proxy server receives a request every--throughonsessionacceptedexpression, we will create a link to the target server at the same time, today's example is the targetMySQLServer, note that the above processing creates the target serverSessionthe process is separate from the real link to the target service (Dispatcheralso provides a tool method for merging both), in order to be able to bind a good upstream-downstream relationship before a link has occurred, bySessionof thechainvariable to express, that is, the currentSessionThe AssociationSession, associating well after starting interestedConnectevent, logical processing is complete.
Step three , Link success events (link to target server in step two)
@Overridepublic void onsessionconnected (Session sess) throws IOException {Session chain = sess.chain;if (chain = = null) { Sess.asyncclose (); return; } if (Sess.isactive () && chain.isactive ()) {sess.register (selectionkey.op_read); Chain.register ( Selectionkey.op_read);}}
One of the core here is when the upstream and downstream are in the link is normal, up and down the Session to start an interesting message read event (write event is automatically triggered in the read processing), why do the reason here is to wait for the upstream and downstream are normal after the start of both message processing, Otherwise, the byte loss will occur.
Fourth Step , processing upstream and downstream data events
@Overrideprotected void OnMessage (Object msg, session Sess) throws IOException {Session chain = sess.chain;if (Chain = = N ull) {sess.asyncclose (); return;} chain.write (msg); }
is not very simple, similar to pipeline, from one end of the data written to the other end.
In principle, 4 steps end, the entire transparent agent is completed, but in order to handle the link exception cleanup, we added the Session cleanup processing, as follows
@Overridepublic void Onsessiontodestroy (Session sess) throws IOException {try {sess.close ();} catch (IOException e) {/ /ignore} if (sess.chain = = null) return; try {sess.chain.close (); sess.chain.chain = Null;sess.chain = null;} catch (IOException e) {}}
Work is to resolve the upstream and downstream link cleanup link.
So far our ioadaptor personalization has been completed, is not very simple, now we have to run up the test, the following code is the last time to talk about the duplicate settings, no new ideas.
public static void Main (string[] args) throws Exception {Dispatcher Dispatcher = new Dispatcher (); Ioadaptor ioadaptor = new Tcpproxyadaptor ("10.17.2.30:3306"); Final Server server = new Server (dispatcher, Ioadaptor, 3306); Server.start ();}
The year, including Slag import and a little comment added up to toss the Line, should run a run, or that sentence, not HelloWorld, You can scale the pressure measurement. See if you have a local agent out of your target service MySQL,gl,hf, GoGoGo.
The full code can be run as follows, or it can be found directly in the Zbus sample code base
https://git.oschina.net/rushmore/zbus/blob/master/src/test/ java/org/zbus/net/tcpproxyadaptor.java?dir=0&filepath=src%2ftest%2fjava%2forg%2fzbus%2fnet% 2ftcpproxyadaptor.java&oid=08abff381d93519485e1c0ee2c35f1d4f8d1814c&sha= A29272ED99A8F21EC19A14B403EBEE53A385E9A4
Package org.zbus.net;import java.io.ioexception;import java.nio.channels.selectionkey;import org.zbus.net.core.Dispatcher;import org.zbus.net.core.IoAdaptor;import org.zbus.net.core.iobuffer;import org.zbus.net.core.session;import org.zbus.proxy.tcpproxyserver; public class tcpproxyadaptor extends ioadaptor {private string Targetaddress;public tcpproxyadaptor (string targetaddress) {this.targetAddress = targetAddress;} Pass does not need to encode and decode, simple return bytebuffer data Public iobuffer encode (object msg) {if (msg Instanceof iobuffer) {IoBuffer buff = (Iobuffer) msg;return buff;} else {throw new runtimeexception ("Message not support");}} Transmission does not need to encode and decode, simple return bytebuffer data Public object decode (iobuffer buff) {if ( Buff.remaining () > 0) {byte[] data = new byte[Buff.remaining ()];buff.readbytes (data); Return iobuffer.wrap (data);} else {return null;}} @Overrideprotected void onsessionaccepted (session sess) throws ioexception { Session target = null;dispatcher dispatcher = sess.getdispatcher (); try { Target = dispatcher.createclientsession (targetaddress, this);} catch (exception e) {sess.asyncclose (); return;} Sess.chain = target;target.chain = sess;dispatcher.registersession (SelectionKey.OP_CONNECT , target);} @Overridepublic void onsessionconnected (session sess) throws IOException { session chain = sess.chain;if (chain == null) { sess.asyncclose (); return; } if (Sess.isactive () && chain.isactive ()) { sess.register ( Selectionkey.op_read); Chain.register (Selectionkey.op_read);}} @Overrideprotected voiD onmessage (object msg, session sess) throws IOException { Session chain = sess.chain;if (chain == null) {sess.asyncclose (); return;} chain.write (msg); @Overridepublic void onsessiontodestroy (session sess) throws ioexception { try {sess.close ();} catch (ioexception e) { //ignore} if (sess.chain == null) Return; try {sess.chain.close (); sess.chain.chain = null;sess.chain = null;} catch (Ioexception e) { }} @SuppressWarnings ("Resource") public static void main (String[] args) throws exception { dispatcher dispatcher = new dispatcher (); ioadaptor ioadaptor = new tcpproxyadaptor (" 10.17.2.30:3306 "); final server server = new server (dispatcher, ioadaptor, 3306); Server.setservername ("Tcpproxyserver"); Server.start ();}}
MySQL transparent proxy (<100 line code) based on Zbus network communication module