As a high-performance asynchronous network development framework, Netty can be used as a framework for the development of various services.
A project of the previous time involves the acquisition of real-time data of hardware equipment, using Netty as the implementation framework of the acquisition service, and using RABBITMQ as the communication message queue for the acquisition service and each other module, the whole service framework diagram is as follows:
The code of the business code and the actual protocol parsing part of the extraction, get the above a simple design, code open source on GitHub, a brief introduction of the following Nettymqserver acquisition service involves several key technology points:
1, device TCP message parsing:
TCP communication is used between nettymqserver and device devices, and the resolution of TCP messages can use Lengthfieldbasedframedecoder (message header and message body), which can solve the problem of "sticky packet" of TCP message effectively.
The message packet parsing diagram is as follows:
Lengthfieldoffset = 0 lengthfieldlength = lengthadjustment -2 (= the length of the Length field) Initialbytestostrip = 0 before DECODE (bytes) after DECODE (bytes) +--------+---------- ------+ +--------+----------------+ | Length | Actual Content |----->| Length | Actual Content | | 0x000e | "HELLO, World" | | 0x000e | "HELLO, World" | +--------+----------------+ +--------+----------------+
The message length in the code is stored in 4 bytes, decoded by Lengthfieldbasedframedecoder (65535,0,4,-4,0), and Netty gets the length of the message from the first 4 bytes in the received data, resulting in a TCP message packet.
2. Send messages to the device:
First, when the connection is created, the connection to the TCP is preserved:
Static final Channelgroup channels = new Defaultchannelgroup ( globaleventexecutor.instance); @Override public void Channelactive (Channelhandlercontext ctx) throws Exception { //A closed channel would be Remo Ved from channelgroup automatically Channels.add (Ctx.channel ()); }
This channel connection is saved with channelgroup each time a channel is Active (connection creation), and when a message needs to be sent to a device, the channelgroup can be traversed to find the corresponding channel. Send a message to the channel:
for (Io.netty.channel.Channel c:echoserverhandler.channels) { bytebuf msg = Unpooled.copiedbuffer ( Message.getbytes ()); C.writeandflush (msg); }
Here are all the connected devices that are sent. When the connection is broken, Channelgroup will automatically remove the connection and do not need to be managed manually.
3. Heartbeat detection
The Netty server needs to know if the device is working properly and can use Netty's Idlestatehandler when a device is unable to collect data due to a power outage or other cause, and the sample code is as follows:
3 minutes for read idlech.pipeline (). AddLast (New Idlestatehandler (3*60,0,0)); Ch.pipeline (). AddLast (New Heartbeathandler ());/** * Handler implementation for heart beating. */public class Heartbeathandler extends channelinboundhandleradapter{ @Override public Void Usereventtriggered (Channelhandlercontext ctx, Object evt) throws Exception { if (evt instanceof idlestateevent { Idlestateevent event = (idlestateevent) evt; if (event.state () = = Idlestate.reader_idle) { //Read timeout System.out.println ("Reader_idle:read timeout From "+ctx.channel (). remoteaddress ()); Ctx.disconnect (); Channel disconnect }}} }
The above setting does not read the data for 3 minutes, triggering a reader_idle event.
4. RABBITMQ message receiving and sending
Nettymqserver messaging is spring AMQP and is easy to use simply by configuring it in a configuration file.
Nettymqserver Message reception can also take spring AMQP, but because the spring-related configuration is not very familiar, the RABBITMQ Client Java API is used to make it more flexible to use MQ:
Connection Connection = Connnectionfactory.newconnection (); Channel channel = Connection.createchannel (); Channel.exchangedeclare (Exchangename, "direct", true, false, NULL); Channel.queuedeclare (QueueName, True, False, false, NULL); Channel.queuebind (QueueName, Exchangename, Routekey); Process the message one by one channel.basicqos (1); Queueingconsumer Queueingconsumer = new Queueingconsumer (channel); Auto-ack is False Channel.basicconsume (QueueName, False, Queueingconsumer); while (true) {Queueingconsumer.delivery Delivery = Queueingconsumer.nextdelivery (); String message = new String (Delivery.getbody ()); Log.debug ("Mq Receiver Get Message"); Send the message to all connected CLients//If you want to send to a specified client, just add//Your own lo GIC and ACK manually//Be aware this channelgroup is thread safe log.info (S Tring.format ("conneted Client Number:%d", EchoServerHandler.channels.size ())); for (Io.netty.channel.Channel c:echoserverhandler.channels) {bytebuf msg = Unpooled.copiedbu Ffer (Message.getbytes ()); C.writeandflush (msg); }//Manually ack to MQ server, the message is consumed. Channel.basicack (Delivery.getenvelope (). Getdeliverytag (), false);
}
The above code reads the data from a queue and uses a manual ack in order to effectively process the data to prevent the exception data from being lost.
How to use RABBITMQ: http://www.cnblogs.com/luxiaoxun/p/3918054.html
Code hosted on GitHub: Https://github.com/luxiaoxun/NettyMqServer
Reference:
http://netty.io/
Http://netty.io/4.0/api/io/netty/handler/codec/LengthFieldBasedFrameDecoder.html
Http://netty.io/4.0/api/io/netty/handler/timeout/IdleStateHandler.html
Message service based on Netty and RABBITMQ