Objective
I wanted to write a test tool before, but there was no good analytical tool, so there was no motivation to write. Recently learned to use Arthas hurriedly put the pressure test tool to fill up, Crazy Crush server performance. The existing connection pool model with Netty can save the work of maintaining the connection. Originally wrote 5 classes, sorted out the code found very simple, the base class on one.
"Connection pooling"
Forget who you borrowed from the code, the client connection pool using Netty Channelpoolmap interface, with the network connection address to do key, with Fixedchannelpool instantiation value, that is, different connection service address corresponding to different connection pool. The upper limit of the theoretical connection number of Fixedchannelpool is Integer.max_value, and the Channelhealthchecker interface is used to determine whether the channel is alive when it is taken out of the pool and spit out to the application layer if it is alive. So the problem of keeping alive is not to worry about themselves.
public class Tcpclientpool {
final eventloopgroup group = new Nioeventloopgroup ();
Final Bootstrap Bootstrap = new Bootstrap ();
private static final int thread_num = Runtime.getruntime (). Availableprocessors ();
Key is the address, value is pool, that is, an address a pool
private abstractchannelpoolmap<inetsocketaddress, simplechannelpool> Poolmap;
The public void build (Channelpoolhandler PoolHandler) throws Exception {
Bootstrap.group (group)
. Channel ( Niosocketchannel.class)
. Option (Channeloption.tcp_nodelay, True)
. Option (Channeloption.so_keepalive, true);
Poolmap = new abstractchannelpoolmap<inetsocketaddress, simplechannelpool> () {
@Override
protected Simplechannelpool Newpool (inetsocketaddress key) {return
new Fixedchannelpool (key), PoolHandler, thread_num);
}} /* The following code omits * *
}
The construction method needs to pass into a Channelpoolhandler interface processing handler, this handler need to implement three methods
void channelreleased (Channel ch) throws Exception;
void channelacquired (Channel ch) throws Exception;
void channelcreated (Channel ch) throws Exception; The most important thing in the processing class is to give channel the codec processor that loads the business protocol.
Public abstract class Basechannelpoolhandler implements Channelpoolhandler {
private handlerconfiguratorinterface Configurator;
Public Basechannelpoolhandler (Handlerconfiguratorinterface configurator) {
this.configurator = configurator;
}
/**
* Because it is a bare channel, it is necessary to configure the codec for him
* only need to be configured once, because channel will be returned to the pool/
@Override public
void channelcreated (Channel ch) throws Exception {
configurator.configchannel (ch);
}
@Override public
void channelreleased (Channel ch) throws Exception {}
@Override public
Void channelacquired (Channel ch) throws Exception {}
}
The class that implements the Handlerconfiguratorinterface interface (a custom interface with only one method public void Configchannel (Channel Channel); Need to assemble codecs for channel objects through the Configchannel method
For the implementation of HTTP
public class Httpconfigurator implements Handlerconfiguratorinterface {
private static final int Http_aggregate_ SIZE = 8192;
@Override public
void Configchannel (Channel ch) {
Socketchannel Channel = (socketchannel) ch;
Channel.config (). Setkeepalive (true);
Channel.config (). Settcpnodelay (true);
Channel.pipeline ()
. AddLast (New Httpclientcodec ())
. AddLast (New Httpobjectaggregator (http_aggregate_size )
. AddLast (New Httpresponsehandler ());
}
This step is consistent with the common Netty processor mounting mode. The last Httpresponsehandler is the handler that handles the response.
"Turn off connection pooling"
The client pool also needs to provide shutdown capability or the program will not exit normally
public void Close () {
poolmap.close ();
Group.shutdowngracefully ();
}
"Send a Message"
Client pools encapsulate methods for asynchronous and synchronous message sending
Asynchronous methods
public void Asyncwritemessage (inetsocketaddress address, Object message) {
Simplechannelpool pool = Getpool );
future<channel> Future = Pool.acquire ();
Gets the message after the instance
Future.addlistener (futurelistener<channel>) F-> {
if (f.issuccess ()) {
Channel ch = F.getnow ();
if (ch.iswritable ()) {
ch.writeandflush (message);
}
Return instance
pool.release (ch);}}
);
Synchronization method
public Boolean syncwritemessage (inetsocketaddress address, Object message) {
Simplechannelpool pool = Getpool ( address);
future<channel> Future = Pool.acquire ();
try {
Channel Channel = Future.get ();
if (channel.iswritable ()) {
channel.writeandflush (message);
Pool.release (channel);
return true;
}
Pool.release (channel);
} catch (Exception e) {
e.printstacktrace ();
}
return false;
}
Other
If you want to send HTTP messages, you need to encapsulate the HTTP message body, otherwise the Netty encoder will throw away
public class Httpmsgcomposer {public
static Object compose (Uri Uri, String msg) throws Exception {
defaultfu Llhttprequest request = new Defaultfullhttprequest (httpversion.http_1_1, Httpmethod.get,
uri.toasciistring (), Unpooled.wrappedbuffer (Msg.getbytes ("UTF-8"));
Build HTTP request
Request.headers (). Set (Httpheadernames.host, Uri.gethost ());
Request.headers (). Set (Httpheadernames.connection, httpheadervalues.keep_alive);
Request.headers (). Set (Httpheadernames.content_length, Request.content (). Readablebytes ());
Request.headers (). Set (Httpheadernames.content_type, "Application/json");
return request;
}
"Call mode"
public class App. {public
static void Main (string[] args) throws Exception {
Tcpclientpool pool = new Tcpclientpoo L ();
Pool.build (New Httpchannelpoolhandler (New Httpconfigurator ()));
String url = "http://163.com";
Uri uri = new uri (URL);
String host = Uri.gethost ();
int port = Uri.getport () = = 1? 80:uri.getport ();
Inetsocketaddress address = new Inetsocketaddress (host, port);
for (int i = 0; i < i++) {
pool.asyncwritemessage (URL, httpmsgcomposer.compose (URI, "Hello World");
} while
(true) {
thread.sleep (1000L);
Pool.close ();
break;
}}}
"Follow-up plan"
1. Release code on GitHub
2. Clients that support UDP
3. Support WebSocket
4. Support Protocol Buff
5. Support Mqtt