Notes on the use of the Apache Mina (iv.)

Source: Internet
Author: User
Tags pack sessions log4j

In the previous article, we introduced how to write our own log filters in Mina, which we implemented ourselves as a compiler.

Practical applications, many applications are not standard Web service or XML, such as China Mobile/unicom/Telecom SMS Gateway program, have their own different protocol implementation, and are based on TCP/IP byte stream. Mina's own codec implemented Textlineencoder and Textlinedecoder, can be processed by line string, for like SMS Gateway program, it is necessary to implement their own codec filter.

We define a simple protocol based on TCP/IP byte throttling to implement packet transmission between client and server. The packet myprotocalpack has a message header and a message body, the message header includes: Length (the total length of the message packet, data type int), flag (message packet flag bit, data type byte), message body content is a string, The actual implementation is handled by byte stream. The source code is as follows:

Package Com.gftech.mytool.mina; Import Com.gftech.util.GFCommon; public class Myprotocalpack {private int length; private byte flag; private String content; public myprotocalpack () {} PU Blic myprotocalpack (byte flag,string content) {this.flag=flag; this.content=content; int len1=content==null?0: Content.getbytes (). length; This.length=5+len1; } public Myprotocalpack (byte[] bs) {if (bs!=null && bs.length>=5) {length=gfcommon.bytes2int ( Gfcommon.bytescopy (BS, 0, 4)); FLAG=BS[4]; Content=new String (Gfcommon.bytescopy (BS, 5, length-5)); } public int GetLength () {return length;} public void SetLength (int length) {this.length = length;} Public byte getf Lag () {return flag.} public void Setflag (Byte flag) {This.flag = flag;} public String getcontent () {return content;} public void SetContent (String content) {this.content = content;} public String toString () {StringBuffer sb=new Stringbu Ffer (); Sb.append ("Len:"). Append (length); Sb.append ("flag:"). Append (flag); Sb.append ("Content:"). Append (content); return sb.tostring (); } }

Looking back, let's take a look at how to use a codec filter for text in Minatimeserver, which adds a class called Protocalcodecfilter in the filter chain, where it calls the A factory method textlinecodecfactory the factory class, creating a Hugh Textlineencoder and Textlinedecoder encoding and decoding device. Let's look at the specific source code: Acceptor.getfilterchain (). AddLast ("Codec", new Protocolcodecfilter (New Textlinecodecfactory ( Charset.forname ("GBK")));

Package org.apache.mina.filter.codec.textline; Import Java.nio.charset.Charset; Import org.apache.mina.core.buffer.BufferDataException; Import org.apache.mina.core.session.IoSession; Import Org.apache.mina.filter.codec.ProtocolCodecFactory; Import Org.apache.mina.filter.codec.ProtocolDecoder; Import Org.apache.mina.filter.codec.ProtocolEncoder; /** * A {@link protocolcodecfactory} that performs encoding and decoding between * A-text line data and a Java string obje Ct. This codec is useful especially * at work with a text-based protocols as SMTP and IMAP. * * @author the Apache MINA Project (dev@mina.apache.org) * @version $Rev $, $Date $ */public class Textlinecodecfactory IM Plements protocolcodecfactory {private final Textlineencoder encoder; private final Textlinedecoder decoder;/** * Create s a new instance with the current default {@link Charset}. * * Public textlinecodecfactory () {This (Charset.defaultcharset ()),}/** * Creates a new instance with the specified {@lin K CHarset}. The * Encoder uses a UNIX {@link linedelimiter} and the decoder uses * the AUTO {@link linedelimiter}. * * @param charset * The CharSet to-use in the encoding and decoding/public textlinecodecfactory (CharSet charset) {ENC oder = new Textlineencoder (charset, Linedelimiter.unix); decoder = new Textlinedecoder (charset, Linedelimiter.auto); }/** * Creates a new instance of Textlinecodecfactory. This is constructor * provides more flexibility for the developer. * * @param charset * the "charset" to "encoding" and decoding * @param encodingdelimiter * The line delimeter for T He encoder * @param decodingdelimiter * "Delimeter" for the decoder/public textlinecodecfactory (Charset Charset, String Encodingdelimiter, String decodingdelimiter) {encoder = new Textlineencoder (charset, Encodingdelimiter); = new Textlinedecoder (charset, Decodingdelimiter); }/** * Creates a new instance of Textlinecodecfactory. This constructor * provides more flexibility for the devEloper. * * @param charset * the "charset" to "encoding" and decoding * @param encodingdelimiter * The line delimeter for T He encoder * @param decodingdelimiter * "Delimeter" for the decoder/public textlinecodecfactory (Charset Charset, Linedelimiter Encodingdelimiter, Linedelimiter decodingdelimiter) {encoder = new Textlineencoder (CharSet, Encodingdelimiter); decoder = new Textlinedecoder (charset, Decodingdelimiter); Public Protocolencoder Getencoder (Iosession sessions) {return encoder.} public Protocoldecoder Getdecoder (iosession ses Sion) {return decoder}/** * Returns the allowed the size of the maximum line. * If the size of the encoded line exceeds this value, the encoder * would throw a {@link illegalargumentexception}. The default value * is {@link integer#max_value}. * <p> * This method does the same job with {@link textlineencoder#getmaxlinelength ()}. * * public int getencodermaxlinelength () {return encoder.getmaxlinelength ();}/** * Sets the Allowed maximum size of the encoded line. * If the size of the encoded line exceeds this value, the encoder * would throw a {@link illegalargumentexception}. The default value * is {@link integer#max_value}. * <p> * This method does the same job with {@link textlineencoder#setmaxlinelength (int)}. * * public void setencodermaxlinelength (int maxlinelength) {encoder.setmaxlinelength (maxlinelength);}/** * Returns the A llowed maximum size is decoded. * If the size is decoded exceeds this value, the * decoder would throw a {@link bufferdataexception}. The default * value is <tt>1024</tt> (1KB). * <p> * This method does the same job with {@link textlinedecoder#getmaxlinelength ()}. * * public int getdecodermaxlinelength () {return decoder.getmaxlinelength ();}/** * Sets the allowed maximum size of Line to be decoded. * If the size is decoded exceeds this value, the * decoder would throw a {@link bufferdataexception}. The DeFault * value is <tt>1024</tt> (1KB). * <p> * This method does the same job with {@link textlinedecoder#setmaxlinelength (int)}. */public void setdecodermaxlinelength (int maxlinelength) {decoder.setmaxlinelength (maxlinelength);}

The

Textlinefactory implements the Protocalcodecfactory interface, which has a coded method Getencoder () and a decoded Method Getdecoder ():

Package Org.apache.mina.filter.codec; Import org.apache.mina.core.session.IoSession; /** * provides {@link Protocolencoder} and {@link Protocoldecoder} which translates * binary or protocol specific data int O Message object and vice versa. * <p> * Please refer to * <a href= ". /.. /.. /.. /.. /xref-examples/org/apache/mina/examples/reverser/reverseprotocolprovider.html "mce_href=" xref-examples/org/ Apache/mina/examples/reverser/reverseprotocolprovider.html "><code>reverserprotocolprovider</code ></a> * example. * * @author the Apache MINA Project (dev@mina.apache.org) * @version $Rev $, $Date $ */public interface Protocolcodecfactor y {/** * Returns a new (or reusable) instance of {@link Protocolencoder} which * encodes message objects into binary or P Rotocol-specific data. * * Protocolencoder Getencoder (iosession session) throws Exception; /** * Returns a new (or reusable) instance of {@link Protocoldecoder} which * decodes binary or protocol-specific data int o mesSage objects. * * Protocoldecoder Getdecoder (iosession session) throws Exception; }

We mainly follow the textlineencoder to achieve the encode () method, in imitation of Textlinedecoder to achieve the decode () can, They implement the Protocalencoder and Protocaldecoder interfaces respectively. We want to write three classes are: Myprotocalcodecfactory,myprotocalencoder,myprotocaldecoder corresponding Textlinecodecfactory,textlineencoder, Textlinedecoder.

Package Com.gftech.mytool.mina; Import Java.nio.charset.Charset; Import org.apache.mina.core.session.IoSession; Import Org.apache.mina.filter.codec.ProtocolCodecFactory; Import Org.apache.mina.filter.codec.ProtocolDecoder; Import Org.apache.mina.filter.codec.ProtocolEncoder; public class Myprotocalcodecfactory implements Protocolcodecfactory {private final Myprotocalencoder encoder; private fi NAL Myprotocaldecoder Decoder; Public myprotocalcodecfactory (Charset Charset) {encoder=new myprotocalencoder (Charset); decoder=new Myprotocaldecoder (CharSet); Public Protocolencoder Getencoder (Iosession sessions) {return encoder.} public Protocoldecoder Getdecoder (iosession ses Sion) {return decoder;}}

Package Com.gftech.mytool.mina; Import Java.nio.charset.Charset; Import Org.apache.mina.core.buffer.IoBuffer; Import org.apache.mina.core.session.IoSession; Import Org.apache.mina.filter.codec.ProtocolEncoderAdapter; Import Org.apache.mina.filter.codec.ProtocolEncoderOutput; public class Myprotocalencoder extends Protocolencoderadapter {private final Charset Charset, public myprotocalencoder (C Harset charset) {This.charset = charset}//Where the encoding of the Myprotocalpack package is implemented and written to the output stream public void encode (iosession session, O Bject message, protocolencoderoutput out) throws Exception {Myprotocalpack value = (myprotocalpack) message; Iobuffer buf = Iobuffer.allocate (Value.getlength ()); Buf.setautoexpand (TRUE); Buf.putint (Value.getlength ()); Buf.put (Value.getflag ()); if (value.getcontent ()!= null) Buf.put (Value.getcontent (). GetBytes ()); Buf.flip (); Out.write (BUF); public void Dispose () throws Exception {}}

Package Com.gftech.mytool.mina; Import Java.nio.charset.Charset; Import Java.nio.charset.CharsetDecoder; Import Org.apache.mina.core.buffer.IoBuffer; Import Org.apache.mina.core.session.AttributeKey; Import org.apache.mina.core.session.IoSession; Import Org.apache.mina.filter.codec.ProtocolDecoder; Import Org.apache.mina.filter.codec.ProtocolDecoderOutput; public class Myprotocaldecoder implements Protocoldecoder {Private final Attributekey context = new Attributekey (getclass (), "context"); Private final Charset Charset; private int maxpacklength = 100; Public Myprotocaldecoder () {This (Charset.defaultcharset ());} public Myprotocaldecoder (Charset Charset) {This.charset = CharSet; public int getmaxlinelength () {return maxpacklength.} public void Setmaxlinelength (int maxlinelength) {if Maxlinelen Gth <= 0) {throw new IllegalArgumentException ("Maxlinelength:" + maxlinelength);} This.maxpacklength = Maxlinelength; Private context GetContext (Iosession sessions) {context ctx; CTX = (context) session.getattribute (context); if (CTX = = null) {CTX = new context (); Session.setattribute (context, CTX);} return CTX; } public void decode (Iosession sessions, Iobuffer in, protocoldecoderoutput out) throws Exception {final int packheadlengt h = 5; Gets the last processing context, in which there may be unhandled data contexts CTX = GetContext (session); The data in the current buffer is appended to the buffer of the context, ctx.append (in); Point the position to 0 position and point the limit to the original position position Iobuffer BUF = Ctx.getbuffer (); Buf.flip (); Then read the protocol of the Packet while (buf.remaining () >= packheadlength) {Buf.mark ();//Read message header part int length = Buf.getint (); byte fla g = Buf.get (); Check the read headers are normal, if not normal, empty the buffer if (length<0 | | Length > Maxpacklength) {buf.clear (); break;}//Read the normal message packet and write to the output stream for Iohandler to process else if (length >= packheadlength && length-packheadlength <= buf.remaining ()) {int oldLimit2 = Buf.limit (); Buf.limit (buf.position () + lengt H-packheadlength); String content = buf.getstring (Ctx.getdecoder ()); Buf.limit (OLDLIMIT2); MyprotocalpackPack = new Myprotocalpack (flag, content); Out.write (Pack); else {//If the message package is incomplete//Buf.reset () to move the pointer back to the start position of the message header (); break;}} if (buf.hasremaining ()) {//move the data to the front of the buffer iobuffer temp = iobuffer.allocate (maxpacklength). Setautoexpand (True); Temp.put (BUF); Temp.flip (); Buf.clear (); Buf.put (temp); else {//If the data has already been processed, clear the Buf.clear ();} public void Finishdecode (Iosession sessions, protocoldecoderoutput out) throws Exception {} public void Dispose (iosession session) throws Exception {Context CTX = [Context] Session.getattribute (context); if (ctx!= null) {Session.removeattrib Ute (context); }//record context, because the data trigger is not large, it is likely to receive only half of the packet//So the context needs to be spelled out in order to fully handle private class contexts {private final charsetdecoder decoder; pri Vate Iobuffer buf; private int matchcount = 0; private int overflowposition = 0; Private context () {decoder = Charset.newdecoder (); buf = Iobuffer.allocate (M). Setautoexpand (TRUE);} public Charsetdeco Der Getdecoder () {return decoder.} public Iobuffer GetBuffer () {return buf;} public int getoverflowposition () {return overflowposition.} public int Getmatchcount () {return matchcount; ID setmatchcount (int matchcount) {this.matchcount = MatchCount;} public void Reset () {overflowposition = 0; matchcount = 0; Decoder.reset (); public void Append (Iobuffer in) {GetBuffer (). put (in);} }

In Myprotocalserver, add your own implemented Log4jfilter and codec filters:

Package Com.gftech.mytool.mina; Import java.io.IOException; Import java.net.InetSocketAddress; Import Java.nio.charset.Charset; Import Org.apache.log4j.Logger; Import Org.apache.log4j.PropertyConfigurator; Import Org.apache.mina.core.service.IoAcceptor; Import Org.apache.mina.core.service.IoHandlerAdapter; Import Org.apache.mina.core.session.IdleStatus; Import org.apache.mina.core.session.IoSession; Import Org.apache.mina.filter.codec.ProtocolCodecFilter; Import Org.apache.mina.transport.socket.nio.NioSocketAcceptor; public class Myprotocalserver {private static final int PORT = 2500 static Logger Logger = Logger.getlogger (myprotocalse Rver.class); public static void Main (string[] args) throws IOException {propertyconfigurator.configure ("conf//log4j.properties"); Ioacceptor acceptor = new Niosocketacceptor (); Log4jfilter lf = new Log4jfilter (logger); Acceptor.getfilterchain (). AddLast ("logger", LF); Acceptor.getfilterchain (). AddLast ("Codec", new Protocolcodecfilter (New MyprotocalcodecFactory (Charset.forname ("GBK"))); Acceptor.getsessionconfig (). Setreadbuffersize (1024); Acceptor.getsessionconfig (). Setidletime (Idlestatus.both_idle, 10); Acceptor.sethandler (New MyHandler ()); Acceptor.bind (New Inetsocketaddress (PORT)); SYSTEM.OUT.PRINTLN ("Start server ...");} Class MyHandler extends Iohandleradapter {static Logger Logger = Logger.getlogger (myhandler.class); @Override public void Exceptioncaught (iosession session, Throwable cause) throws Exception {Cause.printstacktrace ();} @Override public void M Essagereceived (iosession session, Object message) throws Exception {Myprotocalpack pack= (myprotocalpack) message; Logger.debug ("REC:" + Pack);} @Override public void Sessionidle (Iosession sessions, idlestatus status) throws Exception {logger.debug ("IDLE" + Session). Getidlecount (status)); } }

Write a client program to test:

Package Com.gftech.mytool.mina; Import Java.io.DataOutputStream; Import Java.net.Socket; public class Myprotocalclient {public static void main (string[] args) {try {socket socket = new Socket ("127.0.0.1", 250 0); DataOutputStream out = new DataOutputStream (Socket.getoutputstream ()); for (int i = 0; i < 1000 i++) {myprotocalpack pack=new myprotocalpack ((byte) i,i+ "Test Myprotocalaaaaaaaaaaaaaa"); OUT.WR Iteint (Pack.getlength ()); Out.write (Pack.getflag ()); Out.write (Pack.getcontent (). GetBytes ()); Out.flush (); SYSTEM.OUT.PRINTLN (i + "sended"); } thread.sleep (1000); catch (Exception e) {e.printstacktrace ();}} }

You can also use Ioconnector to implement your own client:

Package Com.gftech.mytool.mina; Import java.io.IOException; Import java.net.InetSocketAddress; Import Java.nio.charset.Charset; Import Org.apache.mina.core.future.ConnectFuture; Import Org.apache.mina.core.future.IoFutureListener; Import Org.apache.mina.core.service.IoConnector; Import Org.apache.mina.core.service.IoHandlerAdapter; Import Org.apache.mina.core.session.IdleStatus; Import org.apache.mina.core.session.IoSession; Import Org.apache.mina.filter.codec.ProtocolCodecFilter; Import Org.apache.mina.transport.socket.nio.NioSocketConnector; public class MyProtocalClient2 {private static final String HOST = "192.168.10.8"; private static final int PORT = 2500; Static long counter = 0; Final static int FC1 = 100; static long start = 0; /** * Test using Mina's frame structure * * @param args/public static void main (string[] args) throws IOException {start = System.curren Ttimemillis (); Ioconnector connector = new Niosocketconnector (); Connector.getfilterchain (). AddLast ("Codec", new protocolcodecfiltER (New Myprotocalcodecfactory (Charset.forname ("GBK"))); Connector.sethandler (New TimeClientHandler2 ()); Connector.getsessionconfig (). setreadbuffersize (100); Connector.getsessionconfig (). Setidletime (Idlestatus.both_idle, 10); Connectfuture connfuture = connector.connect (New inetsocketaddress (HOST, PORT)); Connfuture.addlistener (New iofuturelistener<connectfuture> () {public void Operationcomplete (ConnectFuture Future) {try {if (future.isconnected ()) {iosession session = Future.getsession (); SendData (session);} else {System.ou T.PRINTLN ("Connection does not exist");} catch (Exception e) {e.printstacktrace ();}} }); System.out.println ("Start client ..."); public static void SendData (Iosession sessions) throws IOException {for (int i = 0; i < FC1; i++) {String content = "a" FDJKDAFK Zhang Yingpo Test "+ i; Myprotocalpack pack = new Myprotocalpack ((byte) I, content); Session.write (Pack); SYSTEM.OUT.PRINTLN ("Send data: + Pack";}}} Class TimeClientHandler2 extends Iohandleradapter {@Override publicvoid Sessionopened (iosession session) {//Set reader idle time to seconds.//Sessionidle (...) method would be invoked When No. data is read//for seconds. Session.getconfig (). Setidletime (Idlestatus.reader_idle, 60); @Override public void sessionclosed (Iosession sessions) {//Print out total number of bytes read from the remote peer. S YSTEM.ERR.PRINTLN ("Total" + session.getreadbytes () + "byte (s)");} @Override public void Sessionidle (Iosession sessions, idlestatus status) {//Close the connection if reader is idle. if (s) Tatus = = Idlestatus.reader_idle) {Session.close (true);}} @Override public void messagereceived (iosession sessions, Object message) {Myprotocalpack pack = (myprotocalpack) message; System.out.println ("Rec:" + pack);}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.