Java Socket NIO示例总结
Java NIO是非阻塞IO的实现,基于事件驱动,非常适用于服务器需要维持大量连接,但是数据交换量不大的情况,例如一些即时通信的服务等等,它主要有三个部分组成:
- Channels
- Buffers
- Selectors
Channel有两种ServerSocketChannel 和 SocketChannel,ServerSocketChannel可以监听新加入的Socket连接,SocketChannel用于读和写操作。NIO总是把缓冲区的数据写入通道,或者把通道里的数据读出到缓冲区。
Buffer本质上是一块用于读写的内存,只是被包装成了buffer对象,你可以通过allocateDirect()或者allocate()申请内存空间(allocate分配方式产生的内存开销是在JVM中的,而allocateDirect的分配方式产生的开销在JVM之外,以就是系统级的内存分配,使用allocateDirect尤其注意内存溢出问题),Buffer尤其需要理解三个概念,
capacity、position、limit,capacity是固定大小,position是当前读写位置,limit是一个类似于门限的值,用于控制读写的最大的位置。Buffer的常用方法有clear、compact、flip等等,还有比如Buffer的静态方法wrap等等,这些需要根据capacity、position、limit的值进行理解,上面ifeve上的文章就很详细了,我就不再累述了。
Selector用于检测通道,我们通过它才知道哪个通道发生了哪个事件,所以如果需要用selector的话就需要首先进行register,然后遍历SelectionKey对事件进行处理。它一共有SelectionKey.OP_CONNECT、SelectionKey.OP_ACCEPT、SelectionKey.OP_READ、SelectionKey.OP_WRITE四种事件类型。
我在这里只是粗略的总结,关于NIO的概念 http://ifeve.com/java-nio-all/ 可以看这里。
http://blog.csdn.net/ns_code/article/details/15545057 兰亭风雨的这个demo不错,我直接照搬过来了。
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator; public class NIOServer { private static int BUFF_SIZE=1024;
private static int TIME_OUT = 2000;
public static void main(String[] args) throws IOException { Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(10083));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); TCPProtocol protocol = new EchoSelectorProtocol(BUFF_SIZE); while (true) {
if(selector.select(TIME_OUT)==0){
//在等待信道准备的同时,也可以异步地执行其他任务, 这里打印*
System.out.print("*");
continue;
}
Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
while (keyIter.hasNext()) {
SelectionKey key = keyIter.next();
//如果服务端信道感兴趣的I/O操作为accept
if (key.isAcceptable()){
protocol.handleAccept(key);
}
//如果客户端信道感兴趣的I/O操作为read
if (key.isReadable()){
protocol.handleRead(key);
}
//如果该键值有效,并且其对应的客户端信道感兴趣的I/O操作为write
if (key.isValid() && key.isWritable()) {
protocol.handleWrite(key);
} //这里需要手动从键集中移除当前的key
keyIter.remove();
} }
}
}
import java.io.IOException;
import java.nio.channels.SelectionKey; public interface TCPProtocol { void handleAccept(SelectionKey key) throws IOException; void handleRead(SelectionKey key) throws IOException; void handleWrite(SelectionKey key) throws IOException; }
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel; public class EchoSelectorProtocol implements TCPProtocol { private int bufSize; // 缓冲区的长度
public EchoSelectorProtocol(int bufSize){
this.bufSize = bufSize;
} @Override
public void handleAccept(SelectionKey key) throws IOException {
System.out.println("Accept");
SocketChannel socketChannel = ((ServerSocketChannel)key.channel()).accept();
socketChannel.configureBlocking(false);
socketChannel.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufSize)); } @Override
public void handleRead(SelectionKey key) throws IOException {
SocketChannel clntChan = (SocketChannel) key.channel();
//获取该信道所关联的附件,这里为缓冲区
ByteBuffer buf = (ByteBuffer) key.attachment();
buf.clear();
long bytesRead = clntChan.read(buf);
//如果read()方法返回-1,说明客户端关闭了连接,那么客户端已经接收到了与自己发送字节数相等的数据,可以安全地关闭
if (bytesRead == -1){
clntChan.close();
}else if(bytesRead > 0){
//如果缓冲区总读入了数据,则将该信道感兴趣的操作设置为为可读可写
key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
} } @Override
public void handleWrite(SelectionKey key) throws IOException {
// TODO Auto-generated method stub
ByteBuffer buffer=(ByteBuffer) key.attachment();
buffer.flip();
SocketChannel clntChan = (SocketChannel) key.channel();
//将数据写入到信道中
clntChan.write(buffer);
if (!buffer.hasRemaining()){ //如果缓冲区中的数据已经全部写入了信道,则将该信道感兴趣的操作设置为可读
key.interestOps(SelectionKey.OP_READ);
}
//为读入更多的数据腾出空间
buffer.compact(); } }
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; public class NIOClient { public static void main(String[] args) throws IOException {
SocketChannel clntChan = SocketChannel.open();
clntChan.configureBlocking(false);
if (!clntChan.connect(new InetSocketAddress("localhost", 10083))){
//不断地轮询连接状态,直到完成连接
while (!clntChan.finishConnect()){
//在等待连接的时间里,可以执行其他任务,以充分发挥非阻塞IO的异步特性
//这里为了演示该方法的使用,只是一直打印"."
System.out.print(".");
}
} //为了与后面打印的"."区别开来,这里输出换行符
System.out.print("\n");
//分别实例化用来读写的缓冲区 ByteBuffer writeBuf = ByteBuffer.wrap("send send send".getBytes());
ByteBuffer readBuf = ByteBuffer.allocate("send".getBytes().length-1); while (writeBuf.hasRemaining()) {
//如果用来向通道中写数据的缓冲区中还有剩余的字节,则继续将数据写入信道
clntChan.write(writeBuf); }
StringBuffer stringBuffer=new StringBuffer();
//如果read()接收到-1,表明服务端关闭,抛出异常
while ((clntChan.read(readBuf)) >0){
readBuf.flip();
stringBuffer.append(new String(readBuf.array(),0,readBuf.limit()));
readBuf.clear();
} //打印出接收到的数据
System.out.println("Client Received: " + stringBuffer.toString());
//关闭信道
clntChan.close();
}
}
Java Socket NIO示例总结的更多相关文章
- 多线程Java Socket编程示例
package org.merit.test.socket; import java.io.BufferedReader; import java.io.IOException; import jav ...
- Java Socket NIO入门
Java Socket.SocketServer的读写.连接事件监听,都是阻塞式的.Java提供了另外一种非阻塞式读写.连接事件监听方式——NIO.本文简单的介绍一个NIO Socket入门例子,原理 ...
- Java Socket编程示例
一.Socket简介: 1.什么是Socket 网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket.Socket通常用来实现客户方和服务方的连接.Socket ...
- 多线程Java Socket编程示例(转)
这篇做为学习孙卫琴<<Java网络编程精解>>的学习笔记吧.其中采用Java 5的ExecutorService来进行线程池的方式实现多线程,模拟客户端多用户向同一服务器端发送 ...
- Java Socket NIO详解(转)
java选择器(Selector)是用来干嘛的? 2009-01-12 22:21jsptdut | 分类:JAVA相关 | 浏览8901次 如题,不要贴api的,上面的写的我看不懂希望大家能给我个通 ...
- java Socket Tcp示例三则(服务端处理数据、上传文件)
示例一: package cn.itcast.net.p5.tcptest; import java.io.BufferedReader;import java.io.IOException;impo ...
- java socket nio编程
上次写了一个socket的基本编程,但是有个问题,阻塞特别严重,于是小编便去找了nio学习了一下... public class TimeServer { public static void mai ...
- Java Socket NIO
服务端: public class NIOServer { private static final String HOST = "localhost"; private stat ...
- Java socket保存示例(不使用base64)解决中文乱码问题
MultiThreadServer.java package com.my.nubase64; import java.io.BufferedReader; import java.io.Buffer ...
随机推荐
- vue - blog开发学习4
1.新建页面的修改,集成富文本编辑 edit-post.vue(新建和修改都用该组件) <template> <div class="editor"> &l ...
- 57.Queue Reconstruction by Height(按身高重建对列)
Level: Medium 题目描述: Suppose you have a random list of people standing in a queue. Each person is d ...
- YARN学习笔记
分布式资源调度框架 Yet Another Resource Negotiator YARN 不同框架使用相同的系统资源 YARN的核心组件(架构) ResourceManager RM 整个集群同一 ...
- Ubuntu14.04搭建Boa服务
1. 下载 boa 源码 : https://sourceforge.net/projects/boa/ 版本:boa-0.94.13.tar.gz 2. 在Ubuntu 下解压进入 [boa-0.0 ...
- 七、Null、空以及0的区别
一.Null的区别 create database scort use scort create table emp ( empno int primary key, ename ), sal int ...
- java应用之openfire入门篇
前言 openfire是一个聊天服务端,好比qq服务端.本质是个socker server. openfire通讯协议是 xmpp ,什么是xmpp参考百科 https://baike.baidu. ...
- jquey弹出框demo
默认 $('#btn-01').click(function(){ $.dialog({ contentHtml : '<p>我是默认弹出对话框示例展示.我只是用来占位的内容展示,仅仅用来 ...
- Java使用SSH远程访问Windows并执行命令
转载于:http://blog.csdn.net/carolzhang8406/article/details/6760430 https://blog.csdn.net/angel_xiaa/a ...
- Electron-vue实战(三)— 如何在Vuex中管理Mock数据
Electron-vue实战(三)— 如何在Vuex中管理Mock数据 作者:狐狸家的鱼 本文链接:Vuex管理Mock数据 GitHub:sueRimn 在vuex中管理mock数据 关于vuex的 ...
- 编译自己的jdk(使用openJDK源码编译jdk )
找到openjdk网站(http://hg.openjdk.java.net/) 选择需要编译的版本,浏览readme文件,有获取源码及编译步骤 CentOS-7-x86_64-DVD-1804.is ...