Introduction
In the previous article, we introduced the support of multiple different services in the same netty program. Its logic is very simple. It starts multiple subprograms in a main program, and each subprogram binds different services through a BootStrap. port, so as to achieve the purpose of accessing different services by accessing different ports.
However, although multiple ports are highly differentiated, there are still many inconveniences to use. Is it possible to use only one port to unify different protocol services?
Today, I will introduce the method of using the same port to run different protocols in netty. This method is called port unification.
SocksPortUnificationServerHandler
Before explaining custom port unification, let's take a look at the port unification that comes with netty, such as SocksPortUnificationServerHandler.
We know that there are 3 main protocols of SOCKS, namely SOCKS4, SOCKS4a and SOCKS5. They belong to different versions of the same protocol, so different ports must not be used, and the version needs to be judged in the same port.
Specifically, SocksPortUnificationServerHandler inherits from ByteToMessageDecoder, which means that ByteBuf is converted into the corresponding Socks object.
So how did he differentiate between the different versions?
In the decode method, the ByteBuf to be decoded is passed in, and its readerIndex is first obtained:
int readerIndex = in.readerIndex();
We know that the first byte of the SOCKS protocol represents the version, so read the first byte from in ByteBuf as the version number:
byte versionVal = in.getByte(readerIndex);
With the version number, it can be processed by different version numbers. Specifically, for SOCKS4a, Socks4ServerEncoder and Socks4ServerDecoder need to be added:
case SOCKS4a:
logKnownVersion(ctx, version);
p.addAfter(ctx.name(), null, Socks4ServerEncoder.INSTANCE);
p.addAfter(ctx.name(), null, new Socks4ServerDecoder());
break;
For SOCKS5, you need to add two encoders and decoders, Socks5ServerEncoder and Socks5InitialRequestDecoder:
case SOCKS5:
logKnownVersion(ctx, version);
p.addAfter(ctx.name(), null, socks5encoder);
p.addAfter(ctx.name(), null, new Socks5InitialRequestDecoder());
break;
In this way, a port unification is completed. The idea is to judge the version number of the corresponding SOCKS through the first byte of the incoming ByteBuf of the same port, so as to deal with different SOCKS versions.
Custom PortUnificationServerHandler
In this example, we will create a custom Port Unification that accepts both HTTP and gzip requests.
Before that, let's take a look at the magic word of the two protocols, that is to say, if we get a ByteBuf, how can we know whether this is an HTTP protocol or a gzip file transmitted?
Let's take a look at the HTTP protocol first. Here we default to HTTP1.1. For the request protocol of HTTP1.1, the following is an example:
GET / HTTP/1.1
Host: www.flydean.com
The first word of the HTTP request is the method name of the HTTP request. Specifically, there are eight methods, namely:
OPTIONS
Returns the HTTP request methods supported by the server for a specific resource. The functionality of the server can also be tested by sending a '*' request to the web server.
HEAD
Ask the server for a response consistent with the GET request, except that the response body will not be returned. This method makes it possible to obtain meta-information contained in response headers without having to transmit the entire response content.
GET
Make a request to a specific resource. Note: The GET method should not be used in operations that produce "side effects", such as in a Web Application. One of the reasons is that GET may be accessed arbitrarily by web spiders etc.
POST
Submit data to the specified resource for processing requests (such as submitting a form or uploading a file). Data is included in the request body. POST requests may result in the creation of new resources and/or the modification of existing resources.
PUT
Upload its latest content to the specified resource location.
DELETE
Requests the server to delete the resource identified by the Request-URI.
TRACE
Echo the request received by the server, mainly for testing or diagnostics.
CONNECT
The HTTP/1.1 protocol is reserved for proxy servers that can change connections to pipes.
So how many bytes are needed to distinguish these eight methods? You can see that one byte is not enough, because we have POST and PUT, and their first byte is P. So 2 bytes should be used as magic word.
It also has a special format for the gzip protocol, where the first 10 bytes of gzip are the header, where the first byte is 0x1f and the second byte is 0x8b.
In this way, we can also distinguish the gzip protocol with two bytes.
In this way, our handler logic comes out. First take the first two bytes from byteBuf, and then judge them to distinguish whether it is an HTTP request or a gzip request:
private boolean isGzip(int magic1, int magic2) {
return magic1 == 31 && magic2 == 139;
}
private static boolean isHttp(int magic1, int magic2) {
return
magic1 == 'G' && magic2 == 'E' || // GET
magic1 == 'P' && magic2 == 'O' || // POST
magic1 == 'P' && magic2 == 'U' || // PUT
magic1 == 'H' && magic2 == 'E' || // HEAD
magic1 == 'O' && magic2 == 'P' || // OPTIONS
magic1 == 'P' && magic2 == 'A' || // PATCH
magic1 == 'D' && magic2 == 'E' || // DELETE
magic1 == 'T' && magic2 == 'R' || // TRACE
magic1 == 'C' && magic2 == 'O'; // CONNECT
}
Correspondingly, we also need to add the corresponding encoder and decoder to it. For gzip, netty provides ZlibCodecFactory:
p.addLast("gzipEncoder", ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
p.addLast("gzipDecoder", ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
For HTTP, netty also provides HttpRequestDecoder and HttpResponseEncoder and HttpContentCompressor to encode, decode and compress HTTP messages.
p.addLast("decoder", new HttpRequestDecoder());
p.addLast("encoder", new HttpResponseEncoder());
p.addLast("compressor", new HttpContentCompressor());
Summarize
After adding the encoder and decoder, if you want to customize some operations, you only need to add a customized corresponding message handler, which is very convenient.
Examples of this article can be found in: learn-netty4
This article has been included in http://www.flydean.com/38-netty-cust-port-unification/
The most popular interpretation, the most profound dry goods, the most concise tutorials, and many tricks you don't know are waiting for you to discover!
Welcome to pay attention to my official account: "Program those things", understand technology, understand you better!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。