Java NIO入门小例(短连接:客户端和服务器一问一答)
例子中有些写法参考自Netty4源码,建议在实际运用中采用Netty,而非原生的Java NIO(小心epoll空转)。
1. 服务器端
- public class NioServer {
- static SelectorProvider provider = SelectorProvider.provider();
- static Selector selector = null;
- static ServerSocketChannel server = null;
- private static void accept() throws IOException {
- SocketChannel channel = null;
- try {
- channel = server.accept(); // 接受连接
- channel.configureBlocking(false); // 非阻塞模式
- channel.register(selector, SelectionKey.OP_READ, null); // 监听读就绪
- } catch (IOException e) {
- if (channel != null)
- channel.close();
- }
- }
- private static int read(SocketChannel channel) throws IOException {
- try {
- ByteBuffer buffer = ByteBuffer.allocate(1024); // 分配HeapByteBuffer
- int len = channel.read(buffer); // 直到没有数据 || buffer满
- if (len > 0)
- System.out.println(new String(buffer.array(), 0, len, Charset.forName("UTF-8"))); // buffer.array():取HeapByteBuffer中的原始byte[]
- return len;
- } catch (IOException e) {
- if (channel != null)
- channel.close();
- return -1;
- }
- }
- private static void write(SocketChannel channel, String msg) throws IOException {
- try {
- byte[] bytes = msg.getBytes(Charset.forName("UTF-8"));
- ByteBuffer buffer = ByteBuffer.allocate(bytes.length); // 分配HeapByteBuffer
- buffer.put(bytes);
- buffer.flip(); // 切换为读模式
- channel.write(buffer);
- } catch (IOException e) {
- if (channel != null)
- channel.close();
- }
- }
- public static void main(String[] args) throws IOException {
- try {
- selector = provider.openSelector();
- server = provider.openServerSocketChannel();
- server.configureBlocking(false); // 非阻塞模式
- SelectionKey key = server.register(selector, 0, null); // 注册
- if (server.bind(new InetSocketAddress(8888)).socket().isBound()) // 绑定成功
- key.interestOps(SelectionKey.OP_ACCEPT); // 监听连接请求
- while (true) {
- selector.select(); // 监听就绪事件
- Iterator<SelectionKey> it = selector.selectedKeys().iterator();
- while (it.hasNext()) {
- key = it.next();
- it.remove(); // 从已选择键集中移除key
- if (key.isAcceptable()) { // 连接请求到来
- System.out.println("accept...");
- accept();
- } else {
- SocketChannel channel = (SocketChannel) key.channel();
- if (key.isWritable()) { // 写就绪
- System.out.println("write...");
- write(channel, "Hello NioClient!");
- key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); // 取消写就绪,否则会一直触发写就绪(写就绪为代码触发)
- key.channel().close(); // 关闭channel(key将失效)
- }
- if (key.isValid() && key.isReadable()) { // key有效(避免在写就绪时关闭了channel或者取消了key) && 读就绪
- System.out.println("read...");
- int len = read(channel);
- if (len >= 0)
- key.interestOps(key.interestOps() | SelectionKey.OP_WRITE); // 写就绪,准备写数据
- else if (len < 0) // 客户端已关闭socket
- channel.close(); // 关闭channel(key将失效)
- }
- }
- }
- }
- } finally {
- if (server != null)
- server.close();
- if (selector != null)
- selector.close();
- }
- }
- }
2. 客户端
- public class NioClient {
- static SelectorProvider provider = SelectorProvider.provider();
- static Selector selector = null;
- static SocketChannel client = null;
- static boolean close = false;
- private static void write(String msg) throws IOException {
- byte[] bytes = msg.getBytes(Charset.forName("UTF-8"));
- ByteBuffer buffer = ByteBuffer.allocate(bytes.length); // 建立HeapByteBuffer(DirectByteBuffer以后有机会再讨论)
- buffer.put(bytes);
- buffer.flip(); // 切换为读模式
- client.write(buffer);
- }
- private static int read() throws IOException {
- ByteBuffer buffer = ByteBuffer.allocate(1024); // 分配HeapByteBuffer
- int len = client.read(buffer); // 直到没有数据 || buffer满
- if (len > 0)
- System.out.println(new String(buffer.array(), 0, len, Charset.forName("UTF-8"))); // buffer.array():取HeapByteBuffer中的原始byte[]
- return len;
- }
- public static void main(String[] args) throws IOException {
- try {
- selector = provider.openSelector();
- client = provider.openSocketChannel();
- client.configureBlocking(false); // 非阻塞模式
- SelectionKey key = client.register(selector, 0, null); // 注册
- if (client.connect(new InetSocketAddress("127.0.0.1", 8888))) { // 连接成功(很难)
- System.out.println("connected...");
- key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); // 监听读就绪和写就绪(准备写数据)
- } else // 连接失败(正常情况下)
- key.interestOps(SelectionKey.OP_CONNECT); // 监听连接就绪
- while (!close) {
- selector.select(); // 监听就绪事件
- Iterator<SelectionKey> it = selector.selectedKeys().iterator();
- while (it.hasNext()) {
- key = it.next();
- it.remove(); // 从已选择键集移除key
- if (key.isConnectable()) { // 连接就绪
- client.finishConnect(); // 完成连接
- System.out.println("connected...");
- key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT); // 取消监听连接就绪(否则selector会不断提醒连接就绪)
- key.interestOps(key.interestOps() | SelectionKey.OP_READ | SelectionKey.OP_WRITE); // 监听读就绪和写就绪
- } else {
- if (key.isWritable()) { // 写就绪
- System.out.println("write...");
- write("Hello NioServer!");
- key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); // 取消写就绪,否则会一直触发写就绪(写就绪为代码触发)
- }
- if (key.isValid() && key.isReadable()) { // key有效(避免在写就绪时关闭了channel或者取消了key) && 读就绪
- System.out.println("read...");
- if (read() < 0) // 服务器已关闭socket
- close = true; // 退出循环
- }
- }
- }
- }
- } finally {
- if (client != null)
- client.close();
- if (selector != null)
- selector.close();
- }
- }
- }
Java NIO入门小例(短连接:客户端和服务器一问一答)的更多相关文章
- 史上最强Java NIO入门:担心从入门到放弃的,请读这篇!
本文原题“<NIO 入门>,作者为“Gregory M. Travis”,他是<JDK 1.4 Tutorial>等书籍的作者. 1.引言 Java NIO是Java 1.4版 ...
- Java NIO入门(二):缓冲区内部细节
Java NIO 入门(二)缓冲区内部细节 概述 本文将介绍 NIO 中两个重要的缓冲区组件:状态变量和访问方法 (accessor). 状态变量是前一文中提到的"内部统计机制"的 ...
- Java NIO 入门
本文主要记录 Java 中 NIO 相关的基础知识点,以及基本的使用方式. 一.回顾传统的 I/O 刚接触 Java 中的 I/O 时,使用的传统的 BIO 的 API.由于 BIO 设计的类实在太 ...
- Java NIO入门
NIO入门 前段时间在公司里处理一些大的数据,并对其进行分词.提取关键字等.虽说任务基本完成了(效果也不是特别好),对于Java还没入门的我来说前前后后花了2周的时间,我自己也是醉了.当然也有涉及到机 ...
- java NIO入门【原】
server package com.server; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import jav ...
- Java开发之使用websocket实现web客户端与服务器之间的实时通讯
使用websocket实现web客户端与服务器之间的实时通讯.以下是个简单的demo. 前端页面 <%@ page language="java" contentType=& ...
- 网络编程-socket(三)(TCP长连接和UDP短连接、时间服务器)
详解地址:https://www.cnblogs.com/mys6/p/10587673.html TCP server端 import socketsk = socket.socket() # 创建 ...
- JAVA NIO使用非阻塞模式实现高并发服务器
参考:http://blog.csdn.net/zmx729618/article/details/51860699 https://zhuanlan.zhihu.com/p/23488863 ht ...
- HTTP长连接和短连接及应用情景
HTTP短连接 HTTP/1.0中默认使用短连接, 客户端和服务器进行一次HTTP操作, 就需要建立一次连接, 任务结束连接也关闭. 当客户端浏览器访问的web网页中包含其他的web资源时, 每遇到一 ...
随机推荐
- python爬虫模块之调度模块
调度模块也就是对之前所以的模块的一个调度,作为一个流水的入口. 下面的代码的获取数据部分暂时没有写,细节部分在实际开发中,要根据要求再定义,这里说的是使用方法 from savedb import D ...
- BZOJ 3771 生成函数,FFT
Description 我们讲一个悲伤的故事. 从前有一个贫穷的樵夫在河边砍柴. 这时候河里出现了一个水神,夺过了他的斧头,说: “这把斧头,是不是你的?” 樵夫一看:“是啊是啊!” 水神把斧头扔在一 ...
- ACE_Reactor类
.ACE反应器框架简介 反应器(Reactor):用于事件多路分离和分派的体系结构模式 对一个文件描述符指定的文件或设备的操作, 有两种工作方式: 阻塞与非阻塞. 在设计服务端程序时,如果采用阻塞模式 ...
- 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 ...
- 动态计算文本的CGSize
// 计算文本的size -(CGSize)sizeWithText:(NSString *)text maxSize:(CGSize)maxSize fontSize:(CGFloat)fontSi ...
- python traceback
1. Python中的异常栈跟踪 之前在做Java的时候,异常对象默认就包含stacktrace相关的信息,通过异常对象的相关方法printStackTrace()和getStackTrace()等方 ...
- 一台服务器支持多少TCP并发链接
误区一 1.文件句柄---文件描述符 每开一个链接,都要消耗一个文件套接字,当文件描述符用完,系统会返回can't open so many files 这时你需要明白操作系统对可以打开的最大文件数 ...
- Guice2.0的变化——第一部分 新的特性(上)
http://superleo.iteye.com/blog/314816 Private Modules PrivateModules 用于创建并不需要对外可见的绑定对象.当然,这样会使得封装变得更 ...
- Docker概览
Docker.xmind下载
- jquery实现页面加载时删除特定class 的div内前三个字符
jQuery(document).ready(function(){ jQuery("div.groupheader").each(function(){ $(thi ...