例子中有些写法参考自Netty4源码,建议在实际运用中采用Netty,而非原生的Java NIO(小心epoll空转)。

1. 服务器端

  1. public class NioServer {
  2. static SelectorProvider provider = SelectorProvider.provider();
  3. static Selector selector = null;
  4. static ServerSocketChannel server = null;
  5.  
  6. private static void accept() throws IOException {
  7. SocketChannel channel = null;
  8. try {
  9. channel = server.accept(); // 接受连接
  10. channel.configureBlocking(false); // 非阻塞模式
  11. channel.register(selector, SelectionKey.OP_READ, null); // 监听读就绪
  12. } catch (IOException e) {
  13. if (channel != null)
  14. channel.close();
  15. }
  16. }
  17.  
  18. private static int read(SocketChannel channel) throws IOException {
  19. try {
  20. ByteBuffer buffer = ByteBuffer.allocate(1024); // 分配HeapByteBuffer
  21. int len = channel.read(buffer); // 直到没有数据 || buffer满
  22. if (len > 0)
  23. System.out.println(new String(buffer.array(), 0, len, Charset.forName("UTF-8"))); // buffer.array():取HeapByteBuffer中的原始byte[]
  24. return len;
  25. } catch (IOException e) {
  26. if (channel != null)
  27. channel.close();
  28. return -1;
  29. }
  30. }
  31.  
  32. private static void write(SocketChannel channel, String msg) throws IOException {
  33. try {
  34. byte[] bytes = msg.getBytes(Charset.forName("UTF-8"));
  35. ByteBuffer buffer = ByteBuffer.allocate(bytes.length); // 分配HeapByteBuffer
  36. buffer.put(bytes);
  37. buffer.flip(); // 切换为读模式
  38. channel.write(buffer);
  39. } catch (IOException e) {
  40. if (channel != null)
  41. channel.close();
  42. }
  43. }
  44.  
  45. public static void main(String[] args) throws IOException {
  46. try {
  47. selector = provider.openSelector();
  48. server = provider.openServerSocketChannel();
  49. server.configureBlocking(false); // 非阻塞模式
  50. SelectionKey key = server.register(selector, 0, null); // 注册
  51. if (server.bind(new InetSocketAddress(8888)).socket().isBound()) // 绑定成功
  52. key.interestOps(SelectionKey.OP_ACCEPT); // 监听连接请求
  53. while (true) {
  54. selector.select(); // 监听就绪事件
  55. Iterator<SelectionKey> it = selector.selectedKeys().iterator();
  56. while (it.hasNext()) {
  57. key = it.next();
  58. it.remove(); // 从已选择键集中移除key
  59. if (key.isAcceptable()) { // 连接请求到来
  60. System.out.println("accept...");
  61. accept();
  62. } else {
  63. SocketChannel channel = (SocketChannel) key.channel();
  64. if (key.isWritable()) { // 写就绪
  65. System.out.println("write...");
  66. write(channel, "Hello NioClient!");
  67. key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); // 取消写就绪,否则会一直触发写就绪(写就绪为代码触发)
  68. key.channel().close(); // 关闭channel(key将失效)
  69. }
  70. if (key.isValid() && key.isReadable()) { // key有效(避免在写就绪时关闭了channel或者取消了key) && 读就绪
  71. System.out.println("read...");
  72. int len = read(channel);
  73. if (len >= 0)
  74. key.interestOps(key.interestOps() | SelectionKey.OP_WRITE); // 写就绪,准备写数据
  75. else if (len < 0) // 客户端已关闭socket
  76. channel.close(); // 关闭channel(key将失效)
  77. }
  78. }
  79. }
  80. }
  81. } finally {
  82. if (server != null)
  83. server.close();
  84. if (selector != null)
  85. selector.close();
  86. }
  87. }
  88. }

2. 客户端

  1. public class NioClient {
  2. static SelectorProvider provider = SelectorProvider.provider();
  3. static Selector selector = null;
  4. static SocketChannel client = null;
  5. static boolean close = false;
  6.  
  7. private static void write(String msg) throws IOException {
  8. byte[] bytes = msg.getBytes(Charset.forName("UTF-8"));
  9. ByteBuffer buffer = ByteBuffer.allocate(bytes.length); // 建立HeapByteBuffer(DirectByteBuffer以后有机会再讨论)
  10. buffer.put(bytes);
  11. buffer.flip(); // 切换为读模式
  12. client.write(buffer);
  13. }
  14.  
  15. private static int read() throws IOException {
  16. ByteBuffer buffer = ByteBuffer.allocate(1024); // 分配HeapByteBuffer
  17. int len = client.read(buffer); // 直到没有数据 || buffer满
  18. if (len > 0)
  19. System.out.println(new String(buffer.array(), 0, len, Charset.forName("UTF-8"))); // buffer.array():取HeapByteBuffer中的原始byte[]
  20. return len;
  21. }
  22.  
  23. public static void main(String[] args) throws IOException {
  24. try {
  25. selector = provider.openSelector();
  26. client = provider.openSocketChannel();
  27. client.configureBlocking(false); // 非阻塞模式
  28. SelectionKey key = client.register(selector, 0, null); // 注册
  29. if (client.connect(new InetSocketAddress("127.0.0.1", 8888))) { // 连接成功(很难)
  30. System.out.println("connected...");
  31. key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); // 监听读就绪和写就绪(准备写数据)
  32. } else // 连接失败(正常情况下)
  33. key.interestOps(SelectionKey.OP_CONNECT); // 监听连接就绪
  34. while (!close) {
  35. selector.select(); // 监听就绪事件
  36. Iterator<SelectionKey> it = selector.selectedKeys().iterator();
  37. while (it.hasNext()) {
  38. key = it.next();
  39. it.remove(); // 从已选择键集移除key
  40. if (key.isConnectable()) { // 连接就绪
  41. client.finishConnect(); // 完成连接
  42. System.out.println("connected...");
  43. key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT); // 取消监听连接就绪(否则selector会不断提醒连接就绪)
  44. key.interestOps(key.interestOps() | SelectionKey.OP_READ | SelectionKey.OP_WRITE); // 监听读就绪和写就绪
  45. } else {
  46. if (key.isWritable()) { // 写就绪
  47. System.out.println("write...");
  48. write("Hello NioServer!");
  49. key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); // 取消写就绪,否则会一直触发写就绪(写就绪为代码触发)
  50. }
  51. if (key.isValid() && key.isReadable()) { // key有效(避免在写就绪时关闭了channel或者取消了key) && 读就绪
  52. System.out.println("read...");
  53. if (read() < 0) // 服务器已关闭socket
  54. close = true; // 退出循环
  55. }
  56. }
  57. }
  58. }
  59. } finally {
  60. if (client != null)
  61. client.close();
  62. if (selector != null)
  63. selector.close();
  64. }
  65. }
  66. }

Java NIO入门小例(短连接:客户端和服务器一问一答)的更多相关文章

  1. 史上最强Java NIO入门:担心从入门到放弃的,请读这篇!

    本文原题“<NIO 入门>,作者为“Gregory M. Travis”,他是<JDK 1.4 Tutorial>等书籍的作者. 1.引言 Java NIO是Java 1.4版 ...

  2. Java NIO入门(二):缓冲区内部细节

    Java NIO 入门(二)缓冲区内部细节 概述 本文将介绍 NIO 中两个重要的缓冲区组件:状态变量和访问方法 (accessor). 状态变量是前一文中提到的"内部统计机制"的 ...

  3. Java NIO 入门

    本文主要记录 Java 中  NIO 相关的基础知识点,以及基本的使用方式. 一.回顾传统的 I/O 刚接触 Java 中的 I/O 时,使用的传统的 BIO 的 API.由于 BIO 设计的类实在太 ...

  4. Java NIO入门

    NIO入门 前段时间在公司里处理一些大的数据,并对其进行分词.提取关键字等.虽说任务基本完成了(效果也不是特别好),对于Java还没入门的我来说前前后后花了2周的时间,我自己也是醉了.当然也有涉及到机 ...

  5. java NIO入门【原】

    server package com.server; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import jav ...

  6. Java开发之使用websocket实现web客户端与服务器之间的实时通讯

    使用websocket实现web客户端与服务器之间的实时通讯.以下是个简单的demo. 前端页面 <%@ page language="java" contentType=& ...

  7. 网络编程-socket(三)(TCP长连接和UDP短连接、时间服务器)

    详解地址:https://www.cnblogs.com/mys6/p/10587673.html TCP server端 import socketsk = socket.socket() # 创建 ...

  8. JAVA NIO使用非阻塞模式实现高并发服务器

    参考:http://blog.csdn.net/zmx729618/article/details/51860699  https://zhuanlan.zhihu.com/p/23488863 ht ...

  9. HTTP长连接和短连接及应用情景

    HTTP短连接 HTTP/1.0中默认使用短连接, 客户端和服务器进行一次HTTP操作, 就需要建立一次连接, 任务结束连接也关闭. 当客户端浏览器访问的web网页中包含其他的web资源时, 每遇到一 ...

随机推荐

  1. python爬虫模块之调度模块

    调度模块也就是对之前所以的模块的一个调度,作为一个流水的入口. 下面的代码的获取数据部分暂时没有写,细节部分在实际开发中,要根据要求再定义,这里说的是使用方法 from savedb import D ...

  2. BZOJ 3771 生成函数,FFT

    Description 我们讲一个悲伤的故事. 从前有一个贫穷的樵夫在河边砍柴. 这时候河里出现了一个水神,夺过了他的斧头,说: “这把斧头,是不是你的?” 樵夫一看:“是啊是啊!” 水神把斧头扔在一 ...

  3. ACE_Reactor类

    .ACE反应器框架简介 反应器(Reactor):用于事件多路分离和分派的体系结构模式 对一个文件描述符指定的文件或设备的操作, 有两种工作方式: 阻塞与非阻塞. 在设计服务端程序时,如果采用阻塞模式 ...

  4. An In-Depth Look at the HBase Architecture

    https://www.mapr.com/blog/in-depth-look-hbase-architecture An In-Depth Look at the HBase Architectur ...

  5. 动态计算文本的CGSize

    // 计算文本的size -(CGSize)sizeWithText:(NSString *)text maxSize:(CGSize)maxSize fontSize:(CGFloat)fontSi ...

  6. python traceback

    1. Python中的异常栈跟踪 之前在做Java的时候,异常对象默认就包含stacktrace相关的信息,通过异常对象的相关方法printStackTrace()和getStackTrace()等方 ...

  7. 一台服务器支持多少TCP并发链接

    误区一 1.文件句柄---文件描述符 每开一个链接,都要消耗一个文件套接字,当文件描述符用完,系统会返回can't  open so many files 这时你需要明白操作系统对可以打开的最大文件数 ...

  8. Guice2.0的变化——第一部分 新的特性(上)

    http://superleo.iteye.com/blog/314816 Private Modules PrivateModules 用于创建并不需要对外可见的绑定对象.当然,这样会使得封装变得更 ...

  9. Docker概览

    Docker.xmind下载

  10. jquery实现页面加载时删除特定class 的div内前三个字符

    jQuery(document).ready(function(){        jQuery("div.groupheader").each(function(){ $(thi ...