概述
本篇博客通过简单的demo实现netty的使用
netty3
1、添加netty3的maven依赖
<dependency>
<groupId>org.jboss.netty</groupId>
<artifactId>netty</artifactId>
<version>3.2.10.Final</version>
</dependency>
2、服务端的demo
package five.heart3;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.util.HashedWheelTimer;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created with IntelliJ IDEA.
* User: ipaynow
* Date: 17-6-24
* Time: 下午5:56
* netty服务端
*/
public class Server {
public static void main(String[] args){
//服务类
ServerBootstrap serverBootstrap = new ServerBootstrap();
//boss线程监听端口,worker线程负责数据读写
ExecutorService boss = Executors.newCachedThreadPool();
ExecutorService worker = Executors.newCachedThreadPool();
//设置NioSocket工厂
serverBootstrap.setFactory(new NioServerSocketChannelFactory(boss,worker));
final HashedWheelTimer hashedWheelTimer = new HashedWheelTimer(); //定时器
//设置管道的工厂
serverBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline channelPipeline = Channels.pipeline();
//定时器,读超时,写超时,读写超时
channelPipeline.addLast("idle",new IdleStateHandler(hashedWheelTimer,5,5,10));
channelPipeline.addLast("decoder",new StringDecoder());
channelPipeline.addLast("encoder",new StringEncoder());
channelPipeline.addLast("helloHandler",new HelloHandler());
return channelPipeline;
}
});
//netty3中对应设置如下
serverBootstrap.setOption("backlog",1024); //ServerSocketChannel的设置,链接缓冲池的大小
serverBootstrap.setOption("keepAlive",true);//socketChannel的设置,维持链接的活跃,清楚死链接
serverBootstrap.setOption("tcpNoDelay",true); //socketChannel的设置,关闭延迟发送
serverBootstrap.bind(new InetSocketAddress(10101));
System.out.println("start!!!");
}
}
package five.heart3;
import org.jboss.netty.channel.*;
import org.jboss.netty.handler.timeout.IdleState;
import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
import org.jboss.netty.handler.timeout.IdleStateEvent;
/**
* Created with IntelliJ IDEA.
* User: ipaynow
* Date: 17-6-24
* Time: 下午6:17
* To change this template use File | Settings | File Templates.
*/
//public class HelloHandler extends SimpleChannelHandler {
public class HelloHandler extends IdleStateAwareChannelHandler implements ChannelHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
System.out.println(e.getMessage());
}
@Override
public void handleUpstream(final ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if(e instanceof IdleStateEvent){
if(((IdleStateEvent)e).getState() == IdleState.ALL_IDLE){
System.out.println("提玩家下线");
ChannelFuture channelFuture = ctx.getChannel().write("time out,you will close");
channelFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
ctx.getChannel().close();
}
});
}
}else{
super.handleUpstream(ctx,e);
}
}
}
netty5
1、添加netty5的maven依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha2</version>
</dependency>
2、服务端的demo
package five.heart5;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
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;
import io.netty.handler.timeout.IdleStateHandler;
/**
* Created with IntelliJ IDEA.
* User: ipaynow
* Date: 17-6-24
* Time: 下午7:18
* To change this template use File | Settings | File Templates.
*/
public class Server {
public static void main(String[] args){
//服务类
ServerBootstrap serverBootstrap = new ServerBootstrap();
//boss和worker
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
try{
//设置线程池
serverBootstrap.group(boss,worker);
//设置NioSocket工厂
serverBootstrap.channel(NioServerSocketChannel.class);
//设置管道工厂
serverBootstrap.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
channel.pipeline().addLast(new IdleStateHandler(5,5,10));
channel.pipeline().addLast(new StringDecoder());
channel.pipeline().addLast(new StringEncoder());
channel.pipeline().addLast(null);
}
});
//设置参数,TCP参数
serverBootstrap.option(ChannelOption.SO_BACKLOG,2048);//ServerSocketChannel的设置,链接缓冲池的大小
serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE,true);//socketChannel的设置,维持链接的活跃,清楚死链接
serverBootstrap.childOption(ChannelOption.TCP_NODELAY,true);//socketChannel的设置,关闭延迟发送
//绑定端口
ChannelFuture channelFuture = serverBootstrap.bind(10101);
System.out.println("start");
//等待服务端关闭
channelFuture.channel().closeFuture().sync();
}catch (Exception ex){
ex.printStackTrace();
}finally {
//释放资源
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}
package five.heart5;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
/**
* Created with IntelliJ IDEA.
* User: ipaynow
* Date: 17-6-24
* Time: 下午7:29
* To change this template use File | Settings | File Templates.
*/
public class ServerHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void messageReceived(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
System.out.println(msg);
channelHandlerContext.channel().writeAndFlush("hi");
channelHandlerContext.writeAndFlush("hi");
}
@Override
public void userEventTriggered(final ChannelHandlerContext channelHandlerContext,Object evt) throws Exception{
if(evt instanceof IdleStateEvent){
}
}
}
客户端
1、可以使用telnet进行测试上面的服务器端
2、可以编程netty的单client端
package four.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
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;
import java.io.BufferedReader;
import java.io.InputStreamReader;
/**
* Created with IntelliJ IDEA.
* User: ipaynow
* Date: 17-6-24
* Time: 下午4:01
* To change this template use File | Settings | File Templates.
*/
public class Client {
public static void main(String[] args){
//服务类
Bootstrap bootstrap = new Bootstrap();
//worker
EventLoopGroup worker = new NioEventLoopGroup();
try{
//设置线程池
bootstrap.group(worker);
//设置socket工厂
bootstrap.channel(NioSocketChannel.class);
//设置管道
bootstrap.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
channel.pipeline().addLast(new StringDecoder());
channel.pipeline().addLast(new StringEncoder());
channel.pipeline().addLast(new ClientHandler());
}
});
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 10101);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
while (true){
System.out.println("请输入:");
String msg = bufferedReader.readLine();
channelFuture.channel().writeAndFlush(msg);
}
}catch (Exception ex){
ex.printStackTrace();
}finally {
worker.shutdownGracefully();
}
}
}
package four.client;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* Created with IntelliJ IDEA.
* User: ipaynow
* Date: 17-6-24
* Time: 下午4:08
* To change this template use File | Settings | File Templates.
*/
public class ClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void messageReceived(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
System.out.println("客户端收到消息:"+msg);
}
}
3、可以编程netty的多client端
package four.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
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;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created with IntelliJ IDEA.
* User: ipaynow
* Date: 17-6-24
* Time: 下午4:18
* 多连接客户端
*/
public class MultClient {
//服务类
private Bootstrap bootstrap = new Bootstrap();
//会话:Channel对象是线程安全的对象
private List<Channel> channels = new ArrayList<>();
//引用计数
private final AtomicInteger atomicInteger = new AtomicInteger();
//引用计数
public void init(int count){
//worker
EventLoopGroup worker = new NioEventLoopGroup();
//设置线程池
bootstrap.group(worker);
//设置socket工厂
bootstrap.channel(NioSocketChannel.class);
//设置管道
bootstrap.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
channel.pipeline().addLast(new StringDecoder());
channel.pipeline().addLast(new StringEncoder());
channel.pipeline().addLast(new ClientHandler());
}
});
for(int i=1;i<=count;i++){
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1",10101);
channels.add(channelFuture.channel());
}
}
//获取会话
public Channel nextChannel(){
return getFirstActiveChannel(0);
}
private Channel getFirstActiveChannel(int count){
Channel channel = channels.get(Math.abs(atomicInteger.getAndIncrement() % channels.size()));
if(!channel.isActive()){
//重连
reconnect(channel);
if(count>=channels.size()){
throw new RuntimeException("no can use channel");
}
return getFirstActiveChannel(count + 1);
}
return channel;
}
//重连
private void reconnect(Channel channel){
synchronized (channel){
if(channels.indexOf(channel) == -1){
return;
}
Channel newChannel = bootstrap.connect("127.0.0.1",10101).channel();
channels.set(channels.indexOf(channel),newChannel);
}
}
}
package four.client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* Created with IntelliJ IDEA.
* User: ipaynow
* Date: 17-6-24
* Time: 下午4:56
* To change this template use File | Settings | File Templates.
*/
public class Start {
public static void main(String[] args) {
MultClient client = new MultClient();
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 (IOException e) {
e.printStackTrace();
}
}
}
}
总结
关于netty的使用基本上就是上面的内容,在netty的多链接客户端中Channel是线程安全的(新线程时,会写时会将该内容分装成一个任务,给一个单线程池),所以我们当我们多个线程操作同一个Channel对象的时候,是不会出现线程安全的问题,所以,在netty的多链接客户端中采用的是对象组而不是对象池。