在路上

 找回密码
 立即注册
在路上 站点首页 学习 查看内容

分别使用Java IO、NIO、Netty实现的一个Echo Server示例

2017-2-9 13:08| 发布者: zhangjf| 查看: 1120| 评论: 0

摘要: 分别使用Java IO、Java NIO、Netty来实现一个简单的EchoServer(即原样返回客户端的输入信息)。 Java IO int port = 9000;ServerSocket ss = new ServerSocket(port);while (true) { final Socket socket = ss.ac ...

分别使用Java IO、Java NIO、Netty来实现一个简单的EchoServer(即原样返回客户端的输入信息)。

Java IO
  1. int port = 9000;
  2. ServerSocket ss = new ServerSocket(port);
  3. while (true) {
  4. final Socket socket = ss.accept();
  5. new Thread(new Runnable() {
  6. public void run() {
  7. while (true) {
  8. try {
  9. BufferedInputStream in = new BufferedInputStream(
  10. socket.getInputStream());
  11. byte[] buf = new byte[1024];
  12. int len = in.read(buf); // read message from client
  13. String message = new String(buf, 0, len);
  14. BufferedOutputStream out = new BufferedOutputStream(
  15. socket.getOutputStream());
  16. out.write(message.getBytes()); // echo to client
  17. out.flush();
  18. } catch (IOException e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }
  23. }).start();
  24. }
复制代码

实际效果用telnet来演示,如下所示:

  1. $ telnet 127.0.0.1 9000
  2. Trying 127.0.0.1...
  3. Connected to 127.0.0.1.
  4. Escape character is '^]'.
  5. hi
  6. hi
  7. 你好
  8. 你好
复制代码

java io缺点:

需要为每个客户端连接创建一个线程。

Java NIO
  1. ServerSocketChannel ssChannel = ServerSocketChannel.open();
  2. int port = 9001;
  3. ssChannel.bind(new InetSocketAddress(port));
  4. Selector selector = Selector.open();
  5. ssChannel.configureBlocking(false);
  6. ssChannel.register(selector, SelectionKey.OP_ACCEPT); //注册监听连接请求
  7. while (true) {
  8. selector.select();//阻塞 直到某个channel注册的事件被触发
  9. Set<SelectionKey> keys = selector.selectedKeys();
  10. for (SelectionKey key : keys) {
  11. if (key.isAcceptable()) { //客户端连接请求
  12. ServerSocketChannel ssc = (ServerSocketChannel) key
  13. .channel();
  14. SocketChannel sc = ssc.accept();
  15. sc.configureBlocking(false);
  16. sc.register(selector, SelectionKey.OP_READ); //注册监听客户端输入
  17. }
  18. if(key.isReadable()){ //客户端输入
  19. SocketChannel sc = (SocketChannel) key.channel();
  20. ByteBuffer buffer = ByteBuffer.allocate(1024);
  21. sc.read(buffer);
  22. buffer.flip();
  23. sc.write(buffer);
  24. }
  25. }
  26. keys.clear();
  27. }
复制代码

优点:

事件驱动 可通过一个线程来管理多个连接(channel)

但要注意 并不是任何场景都是NIO优于IO的。

Netty
  1. public class NettyEchoServer {
  2. public class EchoServerHandler extends ChannelHandlerAdapter {
  3. @Override
  4. public void channelRead(ChannelHandlerContext ctx, Object msg) { //ehco to client
  5. ctx.write(msg);
  6. ctx.flush();
  7. }
  8. @Override
  9. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  10. // Close the connection when an exception is raised.
  11. cause.printStackTrace();
  12. ctx.close();
  13. }
  14. }
  15. private int port;
  16. public NettyEchoServer(int port) {
  17. this.port = port;
  18. }
  19. public void run() throws Exception {
  20. EventLoopGroup bossGroup = new NioEventLoopGroup();
  21. EventLoopGroup workerGroup = new NioEventLoopGroup();
  22. try {
  23. ServerBootstrap b = new ServerBootstrap();
  24. b.group(bossGroup, workerGroup)
  25. .channel(NioServerSocketChannel.class)
  26. .childHandler(new ChannelInitializer<SocketChannel>() {
  27. @Override
  28. public void initChannel(SocketChannel ch)
  29. throws Exception {
  30. ch.pipeline().addLast(
  31. new EchoServerHandler());
  32. }
  33. }).option(ChannelOption.SO_BACKLOG, 128)
  34. .childOption(ChannelOption.SO_KEEPALIVE, true);
  35. // Bind and start to accept incoming connections.
  36. ChannelFuture f = b.bind(port).sync();
  37. // Wait until the server socket is closed.
  38. // In this example, this does not happen, but you can do that to gracefully shut down your server.
  39. f.channel().closeFuture().sync();
  40. } finally {
  41. workerGroup.shutdownGracefully();
  42. bossGroup.shutdownGracefully();
  43. }
  44. }
  45. public static void main(String[] args) throws Exception {
  46. int port = 9002;
  47. new NettyEchoServer(port).run();
  48. }
  49. }
复制代码

上例摘自官方文档。

优点:

事件驱动的概念比NIO更直观 似乎仅需要继承ChannelHandlerAdapter, 然后覆盖相应方法即可。

参考文档:

http://en.wikipedia.org/wiki/Non-blocking_I/O_(Java)

https://today.java.net/pub/a/today/2007/02/13/architecture-of-highly-scalable-nio-server.html

http://www.javaworld.com/article/2078654/java-se/java-se-five-ways-to-maximize-java-nio-and-nio-2.html

http://netty.io/wiki/user-guide-for-5.x.html

最新评论

小黑屋|在路上 ( 蜀ICP备15035742号-1 

;

GMT+8, 2025-7-10 10:13

Copyright 2015-2025 djqfx

返回顶部