基于Netty实现聊天室
|Word count:1.7k|Reading time:7min|Post View:
基于Netty实现聊天室
Netty简介
Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
也就是说,Netty 是一个基于NIO的客户,服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程。
Netty更多详细介绍
Server端
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
| package chatroom;
import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel;
public class ChatServer {
private int port;
public ChatServer(int port) { this.port = port; }
public void start(){ EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChatServerInitialize()) .option(ChannelOption.SO_BACKLOG, 1024) .option(ChannelOption.SO_KEEPALIVE,true);
ChannelFuture future = bootstrap.bind(port).sync();
System.out.println("服务器启动:"); future.channel().closeFuture().sync(); System.out.println("服务器关闭:"); } catch (InterruptedException e) { e.printStackTrace(); }finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } }
public static void main(String[] args) { new ChatServer(8888).start(); } }
|
ChatServerHandler
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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
| package chatroom;
import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.util.concurrent.GlobalEventExecutor;
public class ChatServerHandler extends SimpleChannelInboundHandler <String>{
public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
@Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { Channel inComing = ctx.channel(); for (Channel channel : channels){ if (channel != inComing) channel.writeAndFlush("[欢迎: " + inComing.remoteAddress() + "] 进入聊天室!\n"); }
channels.add(inComing); }
@Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { Channel outComing = ctx.channel(); for (Channel channel : channels){ if (channel != outComing) channel.writeAndFlush("[再见: ]" + outComing.remoteAddress() + " 离开聊天室!\n"); }
channels.remove(outComing); }
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception { Channel inComing = channelHandlerContext.channel();
for (Channel channel : channels){ if (channel != inComing){ channel.writeAndFlush("[用户" + inComing.remoteAddress() + " 说:]" + s + "\n"); }else { channel.writeAndFlush("[我说:]" + s + "\n"); } } }
@Override public void channelActive(ChannelHandlerContext ctx) throws Exception { Channel inComing = ctx.channel(); System.out.println("[" + inComing.remoteAddress() + "]: 在线"); }
@Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { Channel inComing = ctx.channel(); System.out.println("[" + inComing.remoteAddress() + "]: 离线"); }
@Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { Channel inComing = ctx.channel(); System.out.println(inComing.remoteAddress() + "通讯异常!"); ctx.close(); } }
|
ChatServerInitialize
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
| package chatroom;
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;
public class ChatServerInitialize extends ChannelInitializer<SocketChannel> {
protected void initChannel(SocketChannel socketChannel) throws Exception { System.out.println("客户端连接:" + socketChannel.remoteAddress()); ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast("frame",new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); pipeline.addLast("decode",new StringDecoder()); pipeline.addLast("encode",new StringEncoder()); pipeline.addLast("handler",new ChatServerHandler()); } }
|
Client端
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
| package chatroom;
import echo.EchoClientHandler; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.InetSocketAddress;
public class ChatClient { private String host; private int port;
public ChatClient(String host, int port) { this.host = host; this.port = port; }
public void start() throws InterruptedException { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .handler(new ChatClientInitializer());
Channel channel = b.connect(host,port).sync().channel(); BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
while (true){ channel.writeAndFlush(input.readLine() + "\n"); } } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { group.shutdownGracefully().sync(); } }
public static void main(String[] args) throws InterruptedException { new ChatClient("localhost",8888).start(); } }
|
ChatClientHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package chatroom;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler;
public class ChatClientHandler extends SimpleChannelInboundHandler<String> { protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception { System.out.println(s); } }
|
ChatClientInitializer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package chatroom;
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;
public class ChatClientInitializer extends ChannelInitializer<SocketChannel> { protected void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast("frame",new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); pipeline.addLast("decode",new StringDecoder()); pipeline.addLast("encode",new StringEncoder()); pipeline.addLast("handler",new ChatClientHandler()); } }
|
运行效果
Server端,当有客户端连接时,离开时
Client端,当其他连接发消息,离开时