pom文件
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha1</version>
</dependency>
服务端代码
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* @author zsl
* Netty中,通讯的双方建立连接后,会把数据按照ByteBuf的方式进行传输,
* 例如http协议中,就是通过HttpRequestDecoder对ByteBuf数据流进行处理,转换成http的对象。
*
*/
public class Server {
public static void main(String[] args) {
//EventLoopGroup是用来处理IO操作的多线程事件循环器
//负责接收客户端连接线程
EventLoopGroup bossGroup = new NioEventLoopGroup();
//负责处理客户端i/o事件、task任务、监听任务组
EventLoopGroup workGroup = new NioEventLoopGroup();
//启动 NIO 服务的辅助启动类
ServerBootstrap bootStrap = new ServerBootstrap();
ChannelFuture cf;
bootStrap.group(bossGroup,workGroup)
//配置 Channel
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
//需要编解码,否则无法解析
p.addLast("decoder", new StringDecoder());
p.addLast("encoder", new StringEncoder());
p.addLast(new ServerHandler());
}
});
// 标识当服务器请求处理线程全满时,用于临时存放已完成三次握手的请求的队列的最大长度
.option(ChannelOption.SO_BACKLOG, 1024)
try {
//监听端口
cf = bootStrap.bind(9999).sync();
System.out.println("9999:binded...");
cf.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
//关闭事件流组
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
服务端消息处理
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @author zsl
* 2019-8-12
*/
public class ServerHandler extends ChannelHandlerAdapter {
/**
* 有客户端连接时触发
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("one client connect...");
}
/**
* 断开时触发
* @param ctx
* @throws Exception
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("one client disconnect...");
}
/**
* 接收客户端发送的消息
* @param ctx
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//接收到的消息
System.out.println("客户端:"+msg.toString());
//获取键盘输入
InputStreamReader is = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(is);
String result ="result";
try{
result = br.readLine();
}
catch(IOException e){
e.printStackTrace();
}
//发送消息
ctx.write(result);
ctx.flush();
}
客户端代码
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* @author zsl
* 2019-8-12
*/
public class Client {
public static void main(String[] args) throws Exception {
EventLoopGroup group =new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>(){
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast("decoder", new StringDecoder());
p.addLast("encoder", new StringEncoder());
p.addLast(new ClientHandler());
}
});
ChannelFuture future = b.connect("127.0.0.1", 9999).sync();
future.channel().writeAndFlush("这里是客户端,请求连接服务端!");
future.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
客户端消息处理
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @author zsl
* 2019-8-12
*/
public class ClientHandler extends ChannelHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
/*若把这一句注释掉将无法将event传递给下一个ClientHandler,例如例子中p.addLast(new Client01Handler())后面紧跟着p.addLast(new Client02Handler())
后面的Client02Handler里的方法就不会被触发。
*/
ctx.fireChannelActive();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//接收到的消息
System.out.println("服务端: "+msg);
//获取键盘输入
InputStreamReader is = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(is);
String result ="result";
try{
result = br.readLine();
}
catch(IOException e){
e.printStackTrace();
}
//给服务端回复
ctx.write(result);
ctx.flush();
}
/**
* 当 Netty 由于 IO 错误或者处理器在处理事件时抛出的异常时。
* 在大部分情况下,捕获的异常应该被记录下来并且把关联的 channel 给关闭掉。
* 然而这个方法的处理方式会在遇到不同异常的情况下有不同的实现,
* 比如你可能想在关闭连接之前发送一个错误码的响应消息。
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
测试时先启动服务端,在启动客户端
欢迎大家多多指教