看简单的一个小程序,说明什么是同步调用:所谓的同步调用就是调用一个方法,然后返回一个结果。(这个过程一直是阻塞的,直到返回值)。
而netty中异步编程模型中不是同步调用,读写都是在handler中处理。
关于同步调用和异步调用请参考http://blog.csdn.net/dan_blog/article/details/7897852
服务器端程序
package hello.netty.lyx.com;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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 HelloServer {
public void start(int port) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
// 注册handler
ch.pipeline().addLast(new HelloServerInHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128);
ChannelFuture f = b.bind(port).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
HelloServer server = new HelloServer();
server.start(9090);
}
}
package hello.netty.lyx.com;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
// 该handler是InboundHandler类型
public class HelloServerInHandler extends ChannelInboundHandlerAdapter {
@Override
public boolean isSharable() {
System.out.println("==============handler-sharable==============");
return super.isSharable();
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("==============channel-register==============");
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("==============channel-unregister==============");
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("==============channel-active==============");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("==============channel-inactive==============");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("==============channel-read==============");
ByteBuf result = (ByteBuf) msg;
byte[] result1 = new byte[result.readableBytes()];
// msg中存储的是ByteBuf类型的数据,把数据读取到byte[]中
result.readBytes(result1);
String resultStr = new String(result1);
// 接收并打印客户端的信息
System.out.println("Client said:" + resultStr);
// 释放资源,这行很关键
result.release();
// 向客户端发送消息
String response = "I am ok!";
// 在当前场景下,发送的数据必须转换成ByteBuf数组
ByteBuf encoded = ctx.alloc().buffer(4 * response.length());
encoded.writeBytes(response.getBytes());
ctx.writeAndFlush(encoded);
ctx.close();
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("==============channel-read-complete==============");
ctx.flush();
}
}
客户端程序
package hello.netty.lyx.com;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* 1、Client向Server发送消息:Are you ok?
* 2、Server接收客户端发送的消息,并打印出来。
* 3、Server端向客户端发送消息:I am ok!
* 4、Client接收Server端发送的消息,并打印出来,通讯结束。
*/
public class HelloClient {
StringBuffer message = new StringBuffer();
public String connect(String host, int port) throws Exception {
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
// b.option(ChannelOption.AUTO_READ, false);
b.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new HelloClientIntHandler(message));
}
});
// Start the client.
/**
* await()方法:Waits for this future to be completed.
* Waits for this future until it is done, and rethrows the cause of the failure if this future
* failed.
*/
ChannelFuture f = b.connect(host, port).channel().closeFuture().await();
return message.toString();
} finally {
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
HelloClient client = new HelloClient();
System.out.println(">>>>>>>>>>"+client.connect("127.0.0.1", 9090).toString());
}
}
package hello.netty.lyx.com;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
//InboundHandler类型
public class HelloClientIntHandler extends ChannelInboundHandlerAdapter {
public StringBuffer message;
public HelloClientIntHandler(StringBuffer message) {
this.message = message;
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("==============channel--register==============");
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("==============channel--unregistered==============");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("==============channel--inactive==============");
}
// 连接成功后,向server发送消息
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("==============channel--active==============");
String msg = "Are you ok?";
/**
* 分配ByteBuf
* Return the assigned {@link io.netty.buffer.ByteBufAllocator} which will be used to allocate {@link ByteBuf}s.
*/
ByteBuf encoded = ctx.alloc().buffer(4 * msg.length());
encoded.writeBytes(msg.getBytes());
ctx.write(encoded);
Thread.sleep(10000);
ctx.flush();
}
// 接收server端的消息,并打印出来
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("==============channel--read==============");
ByteBuf result = (ByteBuf) msg;
byte[] result1 = new byte[result.readableBytes()];
result.readBytes(result1);
System.out.println("Server said:" + new String(result1));
message.append(new String(result1));
result.release();
}
}
同步调用体现在这里,使用awaiit方法,一直等待Future的完成。
ChannelFuture f = b.connect(host, port).channel().closeFuture().await();
return message.toString();
public static void main(String[] args) throws Exception {
HelloClient client = new HelloClient();
System.out.println(">>>>>>>>>>"+client.connect("127.0.0.1", 9090).toString());
}
当条用connect方法时,直接返回服务器的数据。
看运行结果,可以体会到netty的同步效果
服务器端打印:
==============handler-sharable==============
==============channel-register==============
==============channel-active==============
==============channel-read==============
Client said:Are you ok?
thread sleep end
==============channel-read-complete==============
==============channel-inactive==============
==============channel-unregister==============
客户端打印
==============channel--register==============
==============channel--active==============
==============channel--read==============
Server said:I am ok!
==============channel--inactive==============
==============channel--unregistered==============
>>>>>>>>>>I am ok!
Process finished with exit code 0
客户端有可能还会出现这种结果:
==============channel--register==============
==============channel--active==============
==============channel--read==============
Server said:I am ok!
>>>>>>>>>>I am ok!
==============channel--inactive==============
==============channel--unregistered==============
可以体会到同步调用的效果,虽然是在netty的异步编程模型上。
==============END==============