Netty框架代码(源码)客户端与服务器

来源:互联网 发布:linux 发送http请求 编辑:程序博客网 时间:2024/05/16 17:42
Netty 是JBoss旗下的io传输的框架,他利用java里面的nio来实现高效,稳定的io传输。
作为io传输,就会有client和server,下面我们看看用netty怎样写client和server
Client:
需要做的事情:
1.配置client启动类
  ClientBootstrap bootstrap = new ClientBootstrap(..)
2.根据不同的协议或者模式为client启动类设置pipelineFactory。
这里telnet pipline Factory 在netty中已经存在,所有直接用
  bootstrap.setPipelineFactory(new TelnetClientPipelineFactory());
也可以自己定义
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() throws Exception {
                return Channels.pipeline(
                        new DiscardClientHandler(firstMessageSize));
            }
        });        
这里DiscardClientHandler 就是自己定义的handler,他需要
public class DiscardServerHandler extends SimpleChannelUpstreamHandler
继承SimpleChannelUpstreamHandler  来实现自己的handler。这里DiscardClientHandler
是处理自己的client端的channel,他的
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
        // Server is supposed to send nothing.  Therefore, do nothing.
    }
  可以看到Discard client不需要接受任何信息
  
3.连接server
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
这里解释一下channelFuture:
在Netty中所有的io操作都是异步的,这也就是意味任何io访问,那么就立即返回处理,并且不能确保
返回的数据全部完成。因此就出现了channelFuture,channelFuture在传输数据时候包括数据和状态两个
部分。他只有Uncompleted和Completed

*                                      +---------------------------+
*                                      | Completed successfully    |
*                                      +---------------------------+
*                                 +---->      isDone() = <b>true</b>      |
* +--------------------------+    |    |   isSuccess() = <b>true</b>      |
* |        Uncompleted       |    |    +===========================+
* +--------------------------+    |    | Completed with failure    |
* |      isDone() = <b>false</b>    |    |    +---------------------------+
* |   isSuccess() = false    |----+---->   isDone() = <b>true</b>         |
* | isCancelled() = false    |    |    | getCause() = <b>non-null</b>     |
* |    getCause() = null     |    |    +===========================+
* +--------------------------+    |    | Completed by cancellation |
*                                 |    +---------------------------+
*                                 +---->      isDone() = <b>true</b>      |
*                                      | isCancelled() = <b>true</b>      |
*                                      +---------------------------+

既然netty io是异步的,那么如何知道channel传送完成有两种方式,一种添加监听器
addListener(ChannelFutureListener) 还有一种直接调用await()方法,这两种方式
有下面的区别
监听器:是以事件模式的,因此代码就需要用事件模式的样式去写,相当复杂,但他是non-blocking模式的
性能方面要比await方法好,而且不会产生死锁情况

await(): 直接方法调用,使用简单,但是他是blocking模式,性能方面要弱而且会产生死锁情况

不要在ChannelHandler 里面调用await(),这是因为通常在channelHandler里的event method是被i/o线程调用的
(除非ChannelPipeline里面有个ExecutionHandler),那么如果这个时候用await就容易产生死锁。

错误样例:
// BAD - NEVER DO THIS
* {@code @Override}
* public void messageReceived({@link ChannelHandlerContext} ctx,{@link MessageEvent} e) {
*     if (e.getMessage() instanceof GoodByeMessage) {
*         {@link ChannelFuture} future = e.getChannel().close();
*         future.awaitUninterruptibly();
*         // Perform post-closure operation
*         // ...
*     }
* }
*
正确样例:
* // GOOD
* {@code @Override}
* public void messageReceived({@link ChannelHandlerContext} ctx,{@link MessageEvent} e) {
*     if (e.getMessage() instanceof GoodByeMessage) {
*         {@link ChannelFuture} future = e.getChannel().close();
*         future.addListener(new {@link ChannelFutureListener}() {
*             public void operationComplete({@link ChannelFuture} future) {
*                 // Perform post-closure operation
*                 // ...
*             }
*         });
*     }
* }

虽然await调用比较危险,但是你确保不是在一个i/o 线程中调用该方法,毕竟await方法还是很简洁方便的,如果
调用该方法是在一个i/o 线程,那么就会抛出 IllegalStateException

await的timeout和i/o timeout区别
需要注意的是这两个timeout是不一样的, #await(long),#await(long, TimeUnit), #awaitUninterruptibly(long),
#awaitUninterruptibly(long, TimeUnit) 这里面的timeout也i/o timeout 没有任何关系,如果io timeout,那么
channelFuture 将被标记为completed with failure,而await的timeout 与future完全没有关系,只是await动作的
timeout。
错误代码
  * // BAD - NEVER DO THIS
* {@link ClientBootstrap} b = ...;
* {@link ChannelFuture} f = b.connect(...);
* f.awaitUninterruptibly(10, TimeUnit.SECONDS);
* if (f.isCancelled()) {
*     // Connection attempt cancelled by user
* } else if (!f.isSuccess()) {
*     // You might get a NullPointerException here because the future
*     // might not be completed yet.
*     f.getCause().printStackTrace();
* } else {
*     // Connection established successfully
* }
*
正确代码
* // GOOD
* {@link ClientBootstrap} b = ...;
* // Configure the connect timeout option.
* <b>b.setOption("connectTimeoutMillis", 10000);</b>
* {@link ChannelFuture} f = b.connect(...);
* f.awaitUninterruptibly();
*
* // Now we are sure the future is completed.
* assert f.isDone();
*
* if (f.isCancelled()) {
*     // Connection attempt cancelled by user
* } else if (!f.isSuccess()) {
*     f.getCause().printStackTrace();
* } else {
*     // Connection established successfully
* }

4.等待或监听数据全部完成
如: future.getChannel().getCloseFuture().awaitUninterruptibly();
5.释放连接等资源
bootstrap.releaseExternalResources();

Server:
1.配置server
ServerBootstrap bootstrap = new ServerBootstrap(
                new NioServerSocketChannelFactory(
                        Executors.newCachedThreadPool(),
                        Executors.newCachedThreadPool()));
                        
2.设置pipeFactory
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() throws Exception {
                return Channels.pipeline(new EchoServerHandler());
            }
        });
    或者
   bootstrap.setPipelineFactory(new HttpServerPipelineFactory());
   
3.绑定sever端端口
bootstrap.bind(new InetSocketAddress(8080));
netty客户端服务器.rar
原创粉丝点击