概述
上次写了一篇netty学习一:用netty构造http服务的小demo
简单介绍如何使用netty编写http程序,而基于socket编程才是netty的强项。
服务端代码
package socket.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class SocketServer {
public static void main(String[] args) throws InterruptedException {
// 接收连接,但是不处理
EventLoopGroup parentGroup = new NioEventLoopGroup();
// 真正处理连接的group
EventLoopGroup childGroup = new NioEventLoopGroup();
try {
//加载Initializer
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(parentGroup, childGroup)
.channel(NioServerSocketChannel.class)
//这里的childHandler是服务于childGroup的,如果直接使用
//handler方法添加处理器,则是服务于parentGroup的
.childHandler(new SocketServerInitializer());
//绑定监听端口
ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
channelFuture.channel().closeFuture().sync();
}
finally {
parentGroup.shutdownGracefully();
childGroup.shutdownGracefully();
}
}
}
package socket.server;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
public class SocketServerInitializer extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//1、添加解码器,用于解释二进制内容
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
//2、编码器,用于计算消息的长度,并把消息长度以二进制的形式追加到消息的前面
pipeline.addLast(new LengthFieldPrepender(4));
//3、socket编程中需要对字符串进行编码解码
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
//4、添加自定义处理器
pipeline.addLast(new SocketServerHandler());
}
}
package socket.server;
import java.util.UUID;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class SocketServerHandler extends SimpleChannelInboundHandler<String>{
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("请求来自:"+ctx.channel().remoteAddress() + ",内容:" + msg);
ctx.channel().writeAndFlush("from server:"+UUID.randomUUID());
}
}
客户端代码
package socket.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
public class SocketClient {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
//加载Initializer
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.handler(new SocketClientInitializer());
//连接服务端
ChannelFuture channelFuture = bootstrap.connect("localhost", 8899).sync();
channelFuture.channel().closeFuture().sync();
}
finally {
eventLoopGroup.shutdownGracefully();
}
}
}
package socket.client;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
public class SocketClientInitializer extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//1、添加解码器,用于解释二进制内容
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
//2、编码器,用于计算消息的长度,并把消息长度以二进制的形式追加到消息的前面
pipeline.addLast(new LengthFieldPrepender(4));
//3、socket编程中需要对字符串进行编码解码
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
//4、添加自定义处理器
pipeline.addLast(new SocketClientHandler());
}
}
package socket.client;
import java.time.LocalDateTime;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class SocketClientHandler extends SimpleChannelInboundHandler<String>{
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("服务器端地址:"+ctx.channel().remoteAddress());
System.out.println("client receive:"+msg);
ctx.channel().writeAndFlush("from client:"+LocalDateTime.now());
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush("你好,服务端");
}
}
当客户端于服务端之间的channel建立后,客户端程序可以在channelActive方法中给服务端发送消息,
服务端接收到消息后,触发SocketServerHandler类的channelRead0方法,给客户端发送消息,
客户端接收到消息后,触发了SocketClientHandler类的channelRead0的方法,给服务端发送消息。
无限发下去。
csdn code 路径
这个项目的源代码放置在csdn code上,欢迎访问。