准备
JDK 8+
Maven 3.2.x
Netty 4.x
Eclipse IDE for Eclipse Committers
package com.moreday.netty_simplechat;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
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;
/**
* @ClassName SimpleChatServer
* @Description TODO(这里用一句话描述这个类的作用)
* @author 寻找手艺人
* @Date 2020年4月16日 上午10:21:03
* @version 1.0.0
*/
public class SimpleChatServer {
private int port;
/**
* @Description TODO(这里用一句话描述这个方法的作用)
*/
public SimpleChatServer(int port) {
// TODO Auto-generated constructor stub
this.port = port;
}
public void run() throws Exception {
//配置NIO线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new SimpleChatServerInitializer())
.childOption(ChannelOption.SO_KEEPALIVE,true);
System.out.println("SimpleChatServer 启动成功 ");
//绑定端口,开始接收进来的链接
ChannelFuture f = b.bind(port).sync();
//等待服务器socket关闭,本例不会发生
f.channel().closeFuture().sync();
} finally {
//优雅关闭
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
System.out.println("SimpleChatServer 优雅关闭");
}
}
public static void main(String[] args) throws Exception {
int port = 8080;
if(args!=null && args.length>0) {
port = Integer.valueOf(args[0]);
}
new SimpleChatServer(port).run();
}
}
package com.moreday.netty_simplechat;
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;
/**
* @ClassName SimpleChatServerHandler
* @Description TODO(这里用一句话描述这个类的作用)
* @author 寻找手艺人
* @Date 2020年4月16日 上午10:12:57
* @version 1.0.0
*/
public class SimpleChatServerHandler extends SimpleChannelInboundHandler<String>{
private ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
/* (非 Javadoc)
* Description:
* @see io.netty.channel.ChannelHandlerAdapter#handlerAdded(io.netty.channel.ChannelHandlerContext)
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
Channel incoming = ctx.channel();
for(Channel channel: channels) {
channel.writeAndFlush("[Server]-"+incoming.remoteAddress()+"加入 \n");
}
channels.add(incoming);
}
/* (非 Javadoc)
* Description:
* @see io.netty.channel.ChannelHandlerAdapter#handlerRemoved(io.netty.channel.ChannelHandlerContext)
*/
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
Channel incoming = ctx.channel();
for(Channel channel:channels) {
channel.writeAndFlush("【Server】- "+incoming.remoteAddress()+"离开 \n");
}
channels.remove(incoming);
}
/* (非 Javadoc)
* Description:
* @see io.netty.channel.ChannelInboundHandlerAdapter#channelActive(io.netty.channel.ChannelHandlerContext)
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
Channel incoming = ctx.channel();
System.out.println("SimpleChatClient"+incoming.remoteAddress()+"在线"+channels.size());
}
/* (非 Javadoc)
* Description:
* @see io.netty.channel.SimpleChannelInboundHandler#channelRead0(io.netty.channel.ChannelHandlerContext, java.lang.Object)
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
// TODO Auto-generated method stub
Channel incoming = ctx.channel();
for(Channel channel:channels) {
if(channel!=incoming) {
channel.writeAndFlush("["+incoming.remoteAddress()+"]"+msg+" \n");
System.out.println("[Server Read]"+msg);
}else {
incoming.writeAndFlush("[self-]"+msg+"\n");
}
}
}
/* (非 Javadoc)
* Description:
* @see io.netty.channel.ChannelInboundHandlerAdapter#channelInactive(io.netty.channel.ChannelHandlerContext)
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
Channel incoming = ctx.channel();
System.out.println("SimpleChatClient"+incoming.remoteAddress()+"掉线");
}
/* (非 Javadoc)
* Description:
* @see io.netty.channel.ChannelInboundHandlerAdapter#exceptionCaught(io.netty.channel.ChannelHandlerContext, java.lang.Throwable)
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// TODO Auto-generated method stub
Channel incoming = ctx.channel();
System.out.println("SimpleChatClient"+incoming.remoteAddress()+"异常");
cause.printStackTrace();
ctx.close();
}
}
package com.moreday.netty_simplechat;
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;
/**
* @ClassName SimpleChatServerInitializer
* @Description TODO(这里用一句话描述这个类的作用)
* @author 寻找手艺人
* @Date 2020年4月16日 上午10:20:20
* @version 1.0.0
*/
public class SimpleChatServerInitializer extends ChannelInitializer<SocketChannel> {
/* (非 Javadoc)
* Description:
* @see io.netty.channel.ChannelInitializer#initChannel(io.netty.channel.Channel)
*/
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SimpleChatServerHandler());
System.out.println("SimpleChatClient:"+ch.remoteAddress() +"连接上");
}
}
package com.moreday.netty_simplechat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* @ClassName SimpleChatClient
* @Description TODO(这里用一句话描述这个类的作用)
* @author 寻找手艺人
* @Date 2020年4月16日 上午10:21:54
* @version 1.0.0
*/
public class SimpleChatClient {
private final int port;
private final String host;
/**
* @Description TODO(这里用一句话描述这个方法的作用)
*/
public SimpleChatClient(int port, String host) {
// TODO Auto-generated constructor stub
this.port = port;
this.host = host;
}
public void connect() throws InterruptedException, IOException {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new SimpleChatClientInitializer());
Channel channel = b.connect(host,port).sync().channel();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while(true) {
channel.writeAndFlush(in.readLine()+"\r\n");
}
} finally {
// TODO: handle finally clause
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 8080;
if(args!=null && args.length>0) {
port = Integer.valueOf(args[0]);
}
new SimpleChatClient(port, "localhost").connect();
}
}
package com.moreday.netty_simplechat;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* @ClassName SimpleChatClientHandler
* @Description TODO(这里用一句话描述这个类的作用)
* @author 寻找手艺人
* @Date 2020年4月16日 上午10:21:21
* @version 1.0.0
*/
public class SimpleChatClientHandler extends SimpleChannelInboundHandler<String>{
/* (非 Javadoc)
* Description:
* @see io.netty.channel.SimpleChannelInboundHandler#channelRead0(io.netty.channel.ChannelHandlerContext, java.lang.Object)
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
// TODO Auto-generated method stub
System.out.println(msg);
}
}
package com.moreday.netty_simplechat;
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.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
/**
* @ClassName SimpleChatClientInitializer
* @Description TODO(这里用一句话描述这个类的作用)
* @author 寻找手艺人
* @Date 2020年4月16日 上午10:21:35
* @version 1.0.0
*/
public class SimpleChatClientInitializer extends ChannelInitializer<SocketChannel>{
/* (非 Javadoc)
* Description:
* @see io.netty.channel.ChannelInitializer#initChannel(io.netty.channel.Channel)
*/
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// TODO Auto-generated method stub
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LoggingHandler(LogLevel.INFO));
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SimpleChatClientHandler());
}
}