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资源时, 每遇到一 ...
随机推荐
- 实战手工注入某站,mssql注入
昨天就搞下来的,但是是工具搞得,为了比赛还是抛弃一阵子的工具吧.内容相对简单,可掠过. 报错得到sql语句: DataSet ds2 = BusinessLibrary.classHelper.Get ...
- 宿主机mount虚拟机镜像文件
转载 mount挂载虚拟机镜像文件 使用mount挂载ubuntu虚拟机所在的img文件的时候,执行: “sudo mount -o loop xxx.img /mnt/xxx”, 系统提示: “mo ...
- monkey测试===修改adb的默认端口
最近电脑上由于公司系统的原因,adb的端口被占用了,但是占用端口的进程是必须启动的,不能被杀死,在网上找了很多办法,大家都是说杀死占用端口的进程.这个方法并不适用我,所以在此给大家一个新的方法.新建一 ...
- [Think] position与anchorPoint关系
1.简介: 最近在学习动画,所以接触到了CAlayer类. 其中的position与anchorPoint关系一感觉一头雾水,网上有篇文章 彻底理解position和anchorPoint关系 里面 ...
- [ python ] hasattr()、getattr()、setattr() 三者关系及运用
hasattr(object, name) 判断一个对象(object)是否存在name属性或方法,返回boolean值,有name属性返回True, 否则返回False In [1]: class ...
- django开发项目实例1--建立一个项目并初步运行
1:进入目标目录新建一个项目 D:\>django-admin.py startproject qiweijie 新建完成后,进入项目文件夹查看目录 D:\>cd qiweijie D:\ ...
- css设置div等标签背景半透明
三种方式: 1. background-color: transparent; 直接设置背景为透明 2.这种是子元素也会跟着变成半透明 /* 背景半透明,1为不透明 */ opacity: 0.5; ...
- 《java并发编程实战》读书笔记9--并发程序的测试
第12章 并发程序的测试 大致分为两类:安全性测试和活跃性测试 12.1 正确性测试 找出需要检查的不变性条件和后验条件.接下来将构建一组测试用例来测试一个有界缓存.程序清单12-1给出了Bounde ...
- 【转载】“惊群”,看看nginx是怎么解决它的
原文:http://blog.csdn.net/russell_tao/article/details/7204260 在说nginx前,先来看看什么是“惊群”?简单说来,多线程/多进程(linux下 ...
- 【转载】WebService到底是什么?
http://blog.csdn.net/wooshn/article/details/8069087/ 一.序言 大家或多或少都听过WebService(Web服务),有一段时间很多计算机期刊.书籍 ...