网站首页 文章专栏 netty实现TCP长连接
netty实现TCP长连接
编辑时间:2018-11-05 11:34:34 作者:田泽 浏览量:903

所用jar包

netty-all-4.1.30.Final.jar 密码:rzwe

NettyConfig.java,存放连接的客户端

import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

public class NettyConfig {

/**
* 存储每一个客户端接入进来时的channel对象
*/
public static ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

}

Server.java,netty配置信息

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class Server {
private int port;
private ServerSocketChannel serverSocketChannel;

public Server(int port){
this.port = port;
bind();
}

private void bind() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//服务端要建立两个group,一个负责接收客户端的连接,一个负责处理数据传输
//连接处理group
EventLoopGroup boss = new NioEventLoopGroup();
//事件处理group
EventLoopGroup worker = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
// 绑定处理group
bootstrap.group(boss, worker).channel(NioServerSocketChannel.class)
//保持连接数
.option(ChannelOption.SO_BACKLOG, 300)
//有数据立即发送
.option(ChannelOption.TCP_NODELAY, true)
//保持连接
.childOption(ChannelOption.SO_KEEPALIVE, true)
//处理新连接
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
// 增加任务处理
ChannelPipeline p = sc.pipeline();
p.addLast(
// //使用了netty自带的编码器和解码器
// new StringDecoder(),
// new StringEncoder(),
//心跳检测,读超时,写超时,读写超时
//new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS),
//自定义的处理器
new ServerHandler());
}
});

//绑定端口,同步等待成功
ChannelFuture future;
try {
future = bootstrap.bind(port).sync();
if (future.isSuccess()) {
serverSocketChannel = (ServerSocketChannel) future.channel();
System.out.println("服务端启动成功,端口:"+port);
} else {
System.out.println("服务端启动失败!");
}

//等待服务监听端口关闭,就是由于这里会将线程阻塞,导致无法发送信息,所以我这里开了线程
future.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
}
finally {
//优雅地退出,释放线程池资源
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
});
thread.start();
}

public void sendMessage(Object msg){
if(serverSocketChannel != null){
serverSocketChannel.writeAndFlush(msg);
}
}

public static void main(String[] args) {
Server server = new Server(8088);
}
}

ServerHandler.java,业务处理

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class ServerHandler extends ChannelInboundHandlerAdapter {

/**
* 客户端与服务端创建连接的时候调用
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("客户端与服务端连接开始...");
NettyConfig.group.add(ctx.channel());
}

/**
* 客户端与服务端断开连接时调用
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("客户端与服务端连接关闭...");
NettyConfig.group.remove(ctx.channel());
}

/**
* 服务端接收客户端发送过来的数据结束之后调用
*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
System.out.println("信息接收完毕...");
}

/**
* 工程出现异常的时候调用
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}

/**
* 服务端处理客户端websocket请求的核心方法,这里接收了客户端发来的信息
*/
@Override
public void channelRead(ChannelHandlerContext channelHandlerContext, Object info) throws Exception {
System.out.println("接收到了:"+info);

ByteBuf buf = (ByteBuf) info;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req, "UTF-8");
System.out.println("接收客户端数据:" + body);
ByteBuf pingMessage = Unpooled.buffer();
pingMessage.writeBytes(req);
channelHandlerContext.writeAndFlush(pingMessage);


//服务端使用这个就能向 每个连接上来的客户端群发消息
//NettyConfig.group.writeAndFlush(info);
// Iterator<Channel> iterator = NettyConfig.group.iterator();
// while(iterator.hasNext()){
// //打印出所有客户端的远程地址
// System.out.println((iterator.next()).remoteAddress());
// }
}


}

使用网络调试助手进行连接测试 下载地址


支付宝打赏 微信打赏

您的支持是我最大的动力。

吐槽区