Netty๋ฅผ ์ด์ฉํ ๋ค์ํ ํ๋กํ ์ฝ ์ฒ๋ฆฌ
Netty๋ ๋ค์ํ ์ผ๋ฐ์ ์ธ ํ๋กํ ์ฝ์ ์ฒ๋ฆฌํ๊ธฐ ์ํ ์ฝ๋ฑ๊ณผ ํธ๋ค๋ฌ๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด๋ฌํ ๋๊ตฌ๋ค์ ์ฌ์ฉํ๋ฉด SSL/TLS ๋ฐ WebSocket ์ง์๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ ๊ตฌํํ๋๋ฐ ์์๋๋ ์๊ฐ๊ณผ ๋
ธ๋ ฅ์ ์ค์ผ ์ ์์ต๋๋ค.
11.1 SSL/TLS๋ก Netty ์ ํ๋ฆฌ์ผ์ด์
๋ณดํธํ๊ธฐ
์ค๋๋ ๋ฐ์ดํฐ ํ๋ผ์ด๋ฒ์๋ ์ค์ํ ๋ฌธ์ ์ด๋ฉฐ, ๊ฐ๋ฐ์๋ก์ ์ฐ๋ฆฌ๋ ์ด๋ฅผ ํด๊ฒฐํ ์ค๋น๊ฐ ๋์ด ์์ด์ผ ํฉ๋๋ค. ์ต์ํ SSL๊ณผ TLS์ ๊ฐ์ ์ํธํ ํ๋กํ ์ฝ์ ๋ํด ์ต์ํด์ ธ์ผ ํฉ๋๋ค.
Netty๋ ์ด๋ฌํ ํ๋กํ ์ฝ์ ์ง์ํ๊ธฐ ์ํด javax.net.ssl
ํจํค์ง๋ฅผ ํ์ฉํ์ฌ ์ํธํ ๋ฐ ๋ณตํธํ๋ฅผ ๊ฐ๋จํ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค. Netty๋ ๋ด๋ถ์ ์ผ๋ก SSLEngine
์ ์ฌ์ฉํ๋ SslHandler
๋ฅผ ์ ๊ณตํ์ฌ ์ด๋ฅผ ๊ตฌํํฉ๋๋ค.
Netty์ OpenSSL/SSLEngine ๊ตฌํ
Netty๋ OpenSSL ๋๊ตฌ๋ฅผ ์ฌ์ฉํ๋ OpenSslEngine
๊ตฌํ์ ์ ๊ณตํฉ๋๋ค. ์ด ํด๋์ค๋ JDK์ SSLEngine
๊ตฌํ๋ณด๋ค ๋ ๋์ ์ฑ๋ฅ์ ์ ๊ณตํฉ๋๋ค. OpenSSL ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ฌ์ฉ ๊ฐ๋ฅํ ๊ฒฝ์ฐ Netty ์ ํ๋ฆฌ์ผ์ด์
์ ๊ธฐ๋ณธ์ ์ผ๋ก OpenSslEngine
์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด JDK ๊ตฌํ์ผ๋ก ๋์ฒด๋ฉ๋๋ค.
๋ฐ์ดํฐ ํ๋ฆ
SSL/TLS ํธ๋ค๋ฌ๋ฅผ ์ฌ์ฉํ ๋ฐ์ดํฐ ํ๋ฆ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
์ํธํ๋ ์์ ๋ฐ์ดํฐ๋ SslHandler
์ ์ํด ๊ฐ๋ก์ฑ์ด์ ธ ๋ณตํธํ๋ ํ ๋ด๋ถ๋ก ์ ๋ฌ๋ฉ๋๋ค.
๋ฐ์ ๋ฐ์ดํฐ๋ SslHandler
๋ฅผ ํตํด ์ํธํ๋ ํ ์ธ๋ถ๋ก ์ ๋ฌ๋ฉ๋๋ค.
SSL/TLS ์ง์ ์ถ๊ฐํ๊ธฐ
๋ค์ ์ฝ๋๋ SslHandler
๋ฅผ ChannelPipeline
์ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค. ChannelInitializer
๋ Channel
์ด ๋ฑ๋ก๋ ๋ ChannelPipeline
์ ์ค์ ํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
Copy public class SslChannelInitializer extends ChannelInitializer<Channel> {
private final SslContext context;
private final boolean startTls;
public SslChannelInitializer(SslContext context, boolean startTls) {
this.context = context;
this.startTls = startTls;
}
@Override
protected void initChannel(Channel ch) throws Exception {
SSLEngine engine = context.newEngine(ch.alloc());
ch.pipeline().addFirst("ssl", new SslHandler(engine, startTls));
}
}
11.2 Netty HTTP/HTTPS ์ ํ๋ฆฌ์ผ์ด์
๊ตฌ์ถ
HTTP/HTTPS๋ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ํ๋กํ ์ฝ ์ค ํ๋์ด๋ฉฐ, Netty๋ ์ด ํ๋กํ ์ฝ์ ์ฌ์ฉํ๊ธฐ ์ํ ๋ค์ํ ์ธ์ฝ๋์ ๋์ฝ๋๋ฅผ ์ ๊ณตํฉ๋๋ค.
HTTP ๋์ฝ๋, ์ธ์ฝ๋ ๋ฐ ์ฝ๋ฑ
Copy public class HttpPipelineInitializer extends ChannelInitializer<Channel> {
private final boolean client;
public HttpPipelineInitializer(boolean client) {
this.client = client;
}
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
if (client) {
pipeline.addLast("decoder", new HttpResponseDecoder());
pipeline.addLast("encoder", new HttpRequestEncoder());
} else {
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("encoder", new HttpResponseEncoder());
}
}
}
HTTP ๋ฉ์์ง ์ง๊ณ
HTTP ์์ฒญ ๋ฐ ์๋ต์ ์ฌ๋ฌ ๋ถ๋ถ์ผ๋ก ๊ตฌ์ฑ๋ ์ ์์ต๋๋ค. Netty๋ ๋ฉ์์ง ๋ถ๋ถ์ FullHttpRequest
๋ฐ FullHttpResponse
๋ฉ์์ง๋ก ๋ณํฉํ๋ ์ง๊ณ๊ธฐ๋ฅผ ์ ๊ณตํฉ๋๋ค.
Copy public class HttpAggregatorInitializer extends ChannelInitializer<Channel> {
private final boolean isClient;
public HttpAggregatorInitializer(boolean isClient) {
this.isClient = isClient;
}
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
if (isClient) {
pipeline.addLast("codec", new HttpClientCodec());
} else {
pipeline.addLast("codec", new HttpServerCodec());
}
pipeline.addLast("aggregator", new HttpObjectAggregator(512 * 1024));
}
}
HTTP ์์ถ
Netty๋ ๋ฐ์ดํฐ ์์ถ์ ์ง์ํ๋ ChannelHandler
๊ตฌํ์ ์ ๊ณตํฉ๋๋ค.
Copy public class HttpCompressionInitializer extends ChannelInitializer<Channel> {
private final boolean isClient;
public HttpCompressionInitializer(boolean isClient) {
this.isClient = isClient;
}
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
if (isClient) {
pipeline.addLast("codec", new HttpClientCodec());
pipeline.addLast("decompressor", new HttpContentDecompressor());
} else {
pipeline.addLast("codec", new HttpServerCodec());
pipeline.addLast("compressor", new HttpContentCompressor());
}
}
}
11.3 WebSocket ์ง์
Netty๋ WebSocket ์ง์์ ์ํ ๊ด๋ฒ์ํ ๋๊ตฌ๋ฅผ ์ ๊ณตํฉ๋๋ค.
Copy public class WebSocketServerInitializer extends ChannelInitializer<Channel> {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(
new HttpServerCodec(),
new HttpObjectAggregator(65536),
new WebSocketServerProtocolHandler("/websocket"),
new TextFrameHandler(),
new BinaryFrameHandler(),
new ContinuationFrameHandler()
);
}
}
11.4 ์ ํด ์ฐ๊ฒฐ ๋ฐ ํ์์์
Netty๋ ์ ํด ์ฐ๊ฒฐ ๋ฐ ํ์์์์ ๊ฐ์งํ๊ธฐ ์ํ ์ฌ๋ฌ ChannelHandler
๊ตฌํ์ ์ ๊ณตํฉ๋๋ค.
IdleStateHandler ์์
Copy public class IdleStateHandlerInitializer extends ChannelInitializer<Channel> {
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new IdleStateHandler(0, 0, 60, TimeUnit.SECONDS));
pipeline.addLast(new HeartbeatHandler());
}
public static final class HeartbeatHandler extends ChannelInboundHandlerAdapter {
private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(
Unpooled.copiedBuffer("HEARTBEAT", CharsetUtil.ISO_8859_1));
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate()).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
super.userEventTriggered(ctx, evt);
}
}
}
}
11.5 ๋์ฉ๋ ๋ฐ์ดํฐ ์ฐ๊ธฐ
Netty๋ NIO์ ์ ๋ก ๋ณต์ฌ ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ ํ์ผ์ ๋ด์ฉ์ ๋คํธ์ํฌ๋ก ์ ์กํ ๋ ๋ณต์ฌ ๋จ๊ณ๋ฅผ ์ ๊ฑฐํฉ๋๋ค.
Copy FileInputStream in = new FileInputStream(file);
FileRegion region = new DefaultFileRegion(in.getChannel(), 0, file.length());
channel.writeAndFlush(region).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
Throwable cause = future.cause();
// ์ค๋ฅ ์ฒ๋ฆฌ
}
}
});
11.6 ๋ฐ์ดํฐ ์ง๋ ฌํ
Netty๋ ๋ค์ํ ๋ฐ์ดํฐ ์ง๋ ฌํ ์ต์
์ ์ ๊ณตํฉ๋๋ค.
JDK ์ง๋ ฌํ
Copy public class JdkSerializationInitializer extends ChannelInitializer<Channel> {
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ObjectEncoder());
pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
}
}
JBoss Marshalling
Copy public class MarshallingInitializer extends ChannelInitializer<Channel> {
private final MarshallerProvider marshallerProvider;
private final UnmarshallerProvider unmarshallerProvider;
public MarshallingInitializer(UnmarshallerProvider unmarshallerProvider, MarshallerProvider marshallerProvider) {
this.unmarshallerProvider = unmarshallerProvider;
this.marshallerProvider = marshallerProvider;
}
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new MarshallingDecoder(unmarshallerProvider));
pipeline.addLast(new MarshallingEncoder(marshallerProvider));
pipeline.addLast(new ObjectHandler());
}
}
ํ๋กํ ์ฝ ๋ฒํผ
Copy public class ProtoBufInitializer extends ChannelInitializer<Channel> {
private final MessageLite lite;
public ProtoBufInitializer(MessageLite lite) {
this.lite = lite;
}
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ProtobufVarint32FrameDecoder());
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(new ProtobufDecoder(lite));
pipeline.addLast(new ObjectHandler());
}
}
Last updated 8 months ago