반응형
공감 및 댓글은 포스팅 하는데 아주아주 큰 힘이 됩니다!! 포스팅 내용이 찾아주신 분들께 도움이 되길 바라며 더 깔끔하고 좋은 포스팅을 만들어 나가겠습니다^^
|
네티를 사용한 채팅 서버에 사용되는 클래스들에 대해서 지난 포스팅에서 알아보았는데요.
이번 포스팅에서는 채팅 서버를 만들어 보겠습니다.
가장 먼저
네티 라이브러리가 필요하겠죠?
위 사이트에 들어가시면 Downloads 탭에
4.1.18 final 버전이 있는데요.
그걸 다운받아서 압축을 풀면 jar폴더에 all-in-one .jar 파일이 있습니다.
그걸 이클립스에서 자바 프로젝트에 외부라이브러리 임포트하시면 준비는 됩니다.
서버에서는 3개의 클래스가 필요합니다.
main() 함수가 있는 ChatServer
채팅 서버의 채널을 초기화하는 ChatServerInitializer
실제 업무를 담당하는 ChatServerHandler
ChatServerInitializer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.DelimiterBasedFrameDecoder; import io.netty.handler.codec.Delimiters; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import io.netty.handler.ssl.SslContext; public class ChatServerInitializer extends ChannelInitializer<SocketChannel> { private final SslContext sslCtx; public ChatServerInitializer(SslContext sslCtx) { this.sslCtx = sslCtx; } @Override protected void initChannel(SocketChannel arg0) throws Exception { ChannelPipeline pipeline = arg0.pipeline(); //pipeline.addLast(sslCtx.newHandler(arg0.alloc())); 보안을 강화. pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); pipeline.addLast(new StringDecoder()); pipeline.addLast(new StringEncoder()); pipeline.addLast(new ChatServerHandler()); } } | cs |
문자열을 주고 받기 위해서는
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
요 세 가지가 필요한데요. 첫번째의 8192는 받을 최대 바이트 수 입니다.
저는 그냥 크게 지정했어요 테스트니까 ㅎㅎ
ChatServerHandler.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | import java.nio.ByteBuffer; import java.nio.charset.Charset; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.util.concurrent.GlobalEventExecutor; public class ChatServerHandler extends ChannelInboundHandlerAdapter { private static final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { System.out.println("handlerAdded of [SERVER]"); Channel incoming = ctx.channel(); for (Channel channel : channelGroup) { //사용자가 추가되었을 때 기존 사용자에게 알림 channel.write("[SERVER] - " + incoming.remoteAddress() + "has joined!\n"); } channelGroup.add(incoming); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // 사용자가 접속했을 때 서버에 표시. System.out.println("User Access!"); } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { System.out.println("handlerRemoved of [SERVER]"); Channel incoming = ctx.channel(); for (Channel channel : channelGroup) { //사용자가 나갔을 때 기존 사용자에게 알림 channel.write("[SERVER] - " + incoming.remoteAddress() + "has left!\n"); } channelGroup.remove(incoming); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { String message = null; message = (String)msg; System.out.println("channelRead of [SERVER]" + message); Channel incoming = ctx.channel(); for (Channel channel : channelGroup) { if (channel != incoming) { //메시지 전달. channel.writeAndFlush("[" + incoming.remoteAddress() + "]" + message + "\n"); } } if ("bye".equals(message.toLowerCase())) { ctx.close(); } } } | cs |
마지막으로
ChatServer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.util.SelfSignedCertificate; public class ChatServer { private final int port; public ChatServer(int port) { super(); this.port = port; } public static void main(String[] args) throws Exception { new ChatServer(5001).run(); } public void run() throws Exception { SelfSignedCertificate ssc = new SelfSignedCertificate(); SslContext sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) .build(); // SslContext를 사용하면 EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChatServerInitializer(sslCtx)); bootstrap.bind(port).sync().channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } } | cs |
서버를 성공적으로 만들어보았습니다.
다음 포스팅에서는
클라이언트를 만들어보겠습니다.
이상입니다.
감사합니다.
반응형
'Netty(네티)' 카테고리의 다른 글
네티 - 이클립스 자바 프로젝트에 네티 라이브러리 추가 및 Source Attachment (0) | 2017.12.15 |
---|---|
Netty 소켓 서버에 안드로이드 접속해서 채팅하기 Netty Socket Server and Android (15) | 2017.12.15 |
Netty(네티) 채팅 서버/클라이언트 [2] : 채팅 클라이언트 만들기 (1) | 2017.12.13 |
Netty(네티) 채팅 서버/클라이언트에 사용되는 클래스 알아보기! (0) | 2017.12.12 |
네티란 ? 자바 네트워크 어플리케이션 프레임워크 (1) | 2017.12.12 |