netty入门
Java中的NIO是一种解决阻塞式IO问题的基本技术,但是NIO的编写对java程序员是有比较高的要求的。那么Netty就是一种简化操作的一个成熟的网络IO编程框架。这里简单介绍一个程序,话不多说,直接上代码。
一、服务器编写
1、Server代码,监听连接:
2、具体的处理客户端连接的代码:
二、客户端编写
1、具体的连接代码:
2、连接成功后,具体的通信代码:
三、结果
先运行server,在运行client即可
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
package com.gerry.netty.server;[/align] import io.netty.bootstrap.ServerBootstrap;
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.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class EchoServer {
private final int port;
public EchoServer( int port) {
this .port = port;
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap sb = new ServerBootstrap();
sb.group(group) // 绑定线程池
.channel(NioServerSocketChannel. class ) // 指定使用的channel
.localAddress( this .port) // 绑定监听端口
.childHandler( new ChannelInitializer<SocketChannel>() { // 绑定客户端连接时候触发操作
@Override
protected void initChannel(SocketChannel ch) throws Exception {
System.out.println( "connected...; Client:" + ch.remoteAddress());
ch.pipeline().addLast( new EchoServerHandler()); // 客户端触发操作
}
});
ChannelFuture cf = sb.bind().sync(); // 服务器异步创建绑定
System.out.println(EchoServer. class + " started and listen on " + cf.channel().localAddress());
cf.channel().closeFuture().sync(); // 关闭服务器通道
} finally {
group.shutdownGracefully().sync(); // 释放线程池资源
}
}
public static void main(String[] args) throws Exception {
new EchoServer( 65535 ).start(); // 启动
}
}
|
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package com.gerry.netty.server;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println( "server channelRead...; received:" + msg);
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println( "server channelReadComplete.." );
// 第一种方法:写一个空的buf,并刷新写出区域。完成后关闭sock channel连接。
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
//ctx.flush(); // 第二种方法:在client端关闭channel连接,这样的话,会触发两次channelReadComplete方法。
//ctx.flush().close().sync(); // 第三种:改成这种写法也可以,但是这中写法,没有第一种方法的好。
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println( "server occur exception:" + cause.getMessage());
cause.printStackTrace();
ctx.close(); // 关闭发生异常的连接
}
}
|
二、客户端编写
1、具体的连接代码:
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
package com.gerry.netty.client;
import io.netty.bootstrap.Bootstrap;
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.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.net.InetSocketAddress;
public class EchoClient {
private final String host;
private final int port;
public EchoClient() {
this ( 0 );
}
public EchoClient( int port) {
this ( "localhost" , port);
}
public EchoClient(String host, int port) {
this .host = host;
this .port = port;
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group) // 注册线程池
.channel(NioSocketChannel. class ) // 使用NioSocketChannel来作为连接用的channel类
.remoteAddress( new InetSocketAddress( this .host, this .port)) // 绑定连接端口和host信息
.handler( new ChannelInitializer<SocketChannel>() { // 绑定连接初始化器
@Override
protected void initChannel(SocketChannel ch) throws Exception {
System.out.println( "connected..." );
ch.pipeline().addLast( new EchoClientHandler());
}
});
System.out.println( "created.." );
ChannelFuture cf = b.connect().sync(); // 异步连接服务器
System.out.println( "connected..." ); // 连接完成
cf.channel().closeFuture().sync(); // 异步等待关闭连接channel
System.out.println( "closed.." ); // 关闭完成
} finally {
group.shutdownGracefully().sync(); // 释放线程池资源
}
}
public static void main(String[] args) throws Exception {
new EchoClient( "127.0.0.1" , 65535 ).start(); // 连接127.0.0.1/65535,并启动
}
}
|
2、连接成功后,具体的通信代码:
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
package com.gerry.netty.client;
import java.nio.charset.Charset;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println( "client channelActive.." );
ctx.writeAndFlush(Unpooled.copiedBuffer( "Netty rocks!" , CharsetUtil.UTF_8)); // 必须有flush
// 必须存在flush
// ctx.write(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));
// ctx.flush();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
System.out.println( "client channelRead.." );
ByteBuf buf = msg.readBytes(msg.readableBytes());
System.out.println( "Client received:" + ByteBufUtil.hexDump(buf) + "; The value is:" + buf.toString(Charset.forName( "utf-8" )));
//ctx.channel().close().sync();// client关闭channel连接
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
|
三、结果
先运行server,在运行client即可