Netty5 最简单的例子 Writing a Discard Server

官方的 user-guide-for-5.x 中第一个例子 [  Writing a Discard Server ]就是最简单的例子


源代码
自带的全部的example代码都可以在官方下载的压缩文件 netty-5.0.0.Alpha1.tar.bz2 中找到,解压该文件后,jar 目录中的 netty-example-5.0.0.Alpha1-sources.jar 作为普通压缩文件解压即可看到源代码。


类的说明
io\netty\example\discard 中能找到4个类

DiscardClient.java -- 客户端入口
DiscardClientHandler.java -- 客户端 handle

DiscardServer.java -- 服务器入口
DiscardServerHandler.java -- 服务器 handle


测试
当然,你可以将源代码编译成JAR文件后,用BAT文件去驱动它,创建客户端,然后连接服务器。为了更看清楚,服务器这里可以直接在ECLIPSE里运行,这样,客户端一连上,就能在服务器端输出些什么到控制台或日志文件中,以确认服务器端真的生效了

可是,有2个问题
1 能否有更简单的客户端来测试
2 现有的服务器代码可是啥都没干,我怎么知道它是正常工作了


简易客户端
事实上,你可以用WINDOWS里自带的telnet来连接。
不过,WIN7默认不开启telnet服务,你需要手动去开启它,这个搜BAIDU可以教会你,我们就不说了。
telnet服务开启后,WIN7中“开始”上的输入栏,输入 cmd,打开的窗口中输入命令 
telnet 127.0.0.1 8089 
注:我的服务器端在本机,所以地址是 127.0.0.1,开启的端口号是 8089


服务器代码的简单修改
官方文档上说在你的 DiscardServerHandler 中这么写

@Override
public void  channelRead(ChannelHandlerContext ctx, Object msg) {
      ByteBuf in = (ByteBuf) msg;
      try {
            while (in.isReadable()) { // (1)
                  System.out.print((char) in.readByte());
                  System.out.flush();
            }
      } finally {
            ReferenceCountUtil.release(msg); // (2)
      }
}

问题是,我们看到的代码
@Override
public void  messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
      // discard
}

方法名不同,估计是不同版本的代码吧,假设我们这么改
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
      ByteBuf in = (ByteBuf) msg;
      try {
            while (in.isReadable()) { // (1)
                  System.out.print((char) in.readByte());
                  System.out.flush();
            }
      } finally {
             ReferenceCountUtil.release(msg); // (2)
      }
}

嗯,会报错,象这样:
五月 23, 2014 5:30:05 下午 io.netty.example.discard.DiscardServerHandler exceptionCaught 
警告: Unexpected exception from downstream. 
io.netty.util.IllegalReferenceCountExc eption: refCnt: 0, decrement: 1 
at io.netty.buffer.AbstractReferenceCounted ByteBuf.release(AbstractReferenceCounted ByteBuf.java:115) 
at io.netty.buffer.WrappedByteBuf.release(WrappedByteBuf.java:819) 
at io.netty.buffer.SimpleLeakAwareByteBuf.release(SimpleLeakAwareByteBuf.java:34) 
at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:68) 
at io.netty.channel.SimpleChannelInboundHand ler.channelRead(SimpleChannelInboundHand ler.java:110) 
at io.netty.channel.ChannelHandlerInvokerUti l.invokeChannelReadNow(ChannelHandlerInvokerUti l.java:74) 
at io.netty.channel.DefaultChannelHandlerInv oker.invokeChannelRead(DefaultChannelHandlerInv oker.java:138) 
at io.netty.channel.DefaultChannelHandlerCon text.fireChannelRead(DefaultChannelHandlerCon text.java:320) 
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:846) 
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:127) 
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:485) 
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptim ized(NioEventLoop.java:452) 
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:346) 
at io.netty.util.concurrent.SingleThreadEventExecuto r$5.run(SingleThreadEventExecuto r.java:794) 
at java.lang.Thread.run(Thread.java:744) 

查了一下,这是因为现在的版本,你不用写这句了:
ReferenceCountUtil.release(msg); 
框架自己帮你做了,你再写这句就会触发这个错误。

所以最后,大概这个方法是这样:
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
    ByteBuf in = (ByteBuf) msg;
    
    while (in.isReadable()) { // (1)
        System.out.print((char) in.readByte());
        System.out.flush();
    }
}

这样,你输入什么,就能在服务器端输出什么了。。。


关于TCP和UDP
socket可以基于TCP,也可以基于UDP。区别在于UDP的不保证数据包都正确收到,所以性能更好,但容错不高。TCP保证不错,所以性能没那么好。
UDP基本只适合做在线视频传输之类,我们的需求应该会是TCP。

那这2种方式在写法上有什么不同?网上搜到这样的说法:

ChannelFactory 的选择上,UDP的通信选择 NioDatagramChannelFactory,TCP的通信我们选择的是NioServerSocketChannelFactory; 
Bootstrap的选择上,UDP选择的是ConnectionlessBootstrap,而TCP选择的是ServerBootstrap。 

对于编解码器decoderEncoder,以及ChannelPipelineFactory,UDP开发与TCP并没有什么区别,在此不做详细介绍。 

对于ChannelHandler是UDP与TCP区别的核心所在。大家都知道UDP是无连接的,也就是说你通过 MessageEvent 参数对象的 getChannel() 方法获取当前会话连接,但是其 isConnected() 永远都返回 false。 
UDP 开发中在消息获取事件回调方法中,获取了当前会话连接 channel 对象后可直接通过 channel 的 write 方法发送数据给对端 channel.write(message, remoteAddress),第一个参数仍然是要发送的消息对象, 
第二个参数则是要发送的对端 SocketAddress 地址对象。 
这里最需要注意的一点是SocketAddress,在TCP通信中我们可以通过channel.getRemoteAddress()获得,但在UDP通信中,我们必须从MessageEvent中通过调用getRemoteAddress()方法获得对端的SocketAddress 地址。 

因此按这个说法看,我们这个例子就是基于TCP的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Netty是一个基于Java的异步事件驱动的网络应用框架,它提供了高性能、可扩展的网络编程能力。Netty的核心是NIO(非阻塞I/O)模型,它允许在单个线程中处理多个并发连接,从而提高了网络应用的吞吐量和性能。 Netty提供了许多开箱即用的组件,其中包括HTTP服务器。通过使用Netty的HTTP服务器组件,您可以轻松地构建和部署自己的HTTP服务器。 下面是一个简单的示例,演示如何使用Netty构建一个简单的HTTP服务器: ```java 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; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; public class HttpServerExample { public static void main(String[] args) throws Exception { // 创建两个EventLoopGroup,一个用于接收连接,一个用于处理连接的I/O操作 EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { // 创建ServerBootstrap实例,用于引导和绑定服务器 ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { // 添加HTTP编解码器 ch.pipeline().addLast(new HttpServerCodec()); // 添加自定义的HTTP请求处理器 ch.pipeline().addLast(new HttpServerHandler()); } }); // 绑定端口并启动服务器 ChannelFuture future = serverBootstrap.bind(8080).sync(); System.out.println("Netty HTTP Server started on port 8080."); // 等待服务器关闭 future.channel().closeFuture().sync(); } finally { // 关闭EventLoopGroup bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } } ``` 在上面的示例中,我们创建了一个`ServerBootstrap`实例,并配置了两个`EventLoopGroup`,一个用于接收连接,一个用于处理连接的I/O操作。然后,我们指定了服务器的通道类型为`NioServerSocketChannel`,并添加了一个`LoggingHandler`用于打印日志。接下来,我们创建了一个`ChannelInitializer`,并在其中添加了一个`HttpServerCodec`用于处理HTTP编解码,以及一个自定义的`HttpServerHandler`用于处理HTTP请求。最后,我们绑定了服务器的端口并启动服务器。 请注意,上述示例中的`HttpServerHandler`是一个自定义的处理器,您可以根据自己的需求来实现它。它负责处理接收到的HTTP请求,并返回相应的HTTP响应。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值