基于netty-all-5.0.0.Alpha2.jar 实现client重连发送消息server响应
Server
package com.zz.hello5;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class Server {
public static void main(String[] args) throws Exception {
new Server(9000).init();
}
// 绑定的端口
private int inetPort;
public Server(int inetPort) {
this.inetPort = inetPort;
}
public void init() {
/** 1、创建ServerBootstrap 和 NioEventLoopGroup
* NioEventLoopGroup 是用来处理I/O操作的多线程事件循环器。
* Netty提供了许多不同的EventLoopGroup的实现用来处理不同传输协议。
* 此例子中实现了一个服务端的应用, 因此会有2个NioEventLoopGroup会被使用.
* 第一个经常被叫做‘boss’,用来接收进来的连接。
* 第二个经常被叫做‘worker’,用来处理已经被接收的连接, 一旦‘boss’接收到连接,就会把连接信息注册到‘worker’上。
* 如何知道多少个线程已经被使用,如何映射到已经创建的Channels上都需要依赖于EventLoopGroup的实现,
* 并且可以通过构造函数来配置他们的关系。
*/
// ServerBootstrap 是一个启动NIO服务的辅助启动类
ServerBootstrap bootstrap = new ServerBootstrap();
// boss 和 worker(NioEventLoopGroup内会创建线程池)
NioEventLoopGroup boss = new NioEventLoopGroup();
NioEventLoopGroup worker = new NioEventLoopGroup();
try {
// 链式操作
bootstrap.group(boss, worker) /** 2、设置线程池 */
/** 3、ServerSocketChannel以NIO的selector为基础进行实现的,用来接收新的连接 */
.channel(NioServerSocketChannel.class)
/** 4、绑定i/o事件处理类
* 这里的事件处理类经常会被用来处理一个最近的已经接收的Channel。
* ChannelInitializer是一个特殊的处理类,的目的是帮助使用者配置一个新的Channel。
* 也许你想通过增加一些处理类比如NettyServerHandler来配置一个新的Channel或者其对应的ChannelPipeline来实现你的网络程序。
* 当你的程序变的复杂时,可能你会增加更多的处理类到pipline上,然后提取这些匿名类到最顶层的类上。
*/
.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch)
throws Exception {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new StringEncoder());
ch.pipeline().addLast(new ServerHandler());
}
})
/** 5、
* serverSocketchannel的设置,链接缓冲池的大小
* option()是提供给NioServerSocketChannel用来接收进来的连接
*/
.option(ChannelOption.SO_BACKLOG, 2048)
/**
* socketchannel的设置,维持链接的活跃,清除死链接
* childOption()是提供给由父管道ServerChannel接收到的连接,在这个例子中也是NioServerSocketChannel。
*/
.childOption(ChannelOption.SO_KEEPALIVE, true)
/** 关闭延迟发送 */
.childOption(ChannelOption.TCP_NODELAY, true);
/** 6、服务器启动后绑定监听端口,同步等待成功。主要用于异步操作的通知回调 回调处理用的ServerHandler */
ChannelFuture future = bootstrap.bind(inetPort).sync();
System.out.println("server start...");
/** 7、服务器等待通道关闭,因为使用 sync(),所以关闭操作也会被阻塞 */
future.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放资源
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}
/**
* 网络事件处理
*/
class ServerHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void messageReceived(ChannelHandlerContext ctx, String msg)
throws Exception {
System.out.println(msg);
// ctx.channel().writeAndFlush("hi");
ctx.writeAndFlush("Hi I'm Server!");
}
}
client重连
package com.zz.hello5;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* 客户端多次连接
*/
public class ClientMultiConn {
public static void main(String[] args) {
ClientMultiConn client = new ClientMultiConn("192.168.2.112", 9000);
client.init(5);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(System.in));
while (true) {
try {
System.out.println("请输入:");
String msg = bufferedReader.readLine();
client.nextChannel().writeAndFlush(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 创建 Bootstrap 对象用来引导启动客户端
private Bootstrap bootstrap = new Bootstrap();
// 创建对象组(回话)
private List<Channel> channels = new ArrayList<>();
// 自动计数器
private final AtomicInteger atomic = new AtomicInteger();
private String inetHost;
private int inetPort;
public ClientMultiConn(String inetHost, int inetPort) {
super();
this.inetHost = inetHost;
this.inetPort = inetPort;
}
public void init(int num) {
// worker(client 不需要接收连接)
NioEventLoopGroup worker = new NioEventLoopGroup();
// 链式操作
this.bootstrap.group(worker) // 线程组
//
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new StringEncoder());
ch.pipeline().addLast(new ClientHandler());
}
});
for (int i = 0; i < num; i++) {
ChannelFuture future = this.bootstrap.connect(inetHost, inetPort);
this.channels.add(future.channel());
}
}
/**
* 获取会话
* @return
*/
public Channel nextChannel() {
return this.getFirstActiveChannel(0);
}
private Channel getFirstActiveChannel(int i) {
Channel channel = this.channels.get(
Math.abs(this.atomic.getAndIncrement() % this.channels.size()));
if (!channel.isActive()) {
// 重新连接
this.reconnect(channel);
if (i >= this.channels.size()) {
throw new RuntimeException("no can use channel");
}
return this.getFirstActiveChannel(i + 1);
}
return channel;
}
/** 重连 */
private void reconnect(Channel channel) {
synchronized (channel) {
if (-1 == this.channels.indexOf(channel)) {
return;
}
Channel newChannel = this.bootstrap.connect(inetHost, inetPort)
.channel();
channels.set(this.channels.indexOf(channel), newChannel);
}
}
}
/**
* client 消息处理
*/
class ClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void messageReceived(ChannelHandlerContext ctx, String msg)
throws Exception {
System.out.println("client received : " + msg);
}
}