Java Socket IO(BIO、NIO)
总结下Java socket IO。首先是各种IO的定义,这个定义似乎也是众说纷纭。我按照stackoverflow上面的解释:
IO有两种分法:按照阻塞或者按照同步。按照阻塞,有阻塞IO和非阻塞IO。按照同步就是同步IO或者异步IO。我们可以认为阻塞IO和同步IO相等,而非阻塞IO和异步IO不同。
阻塞IO或者同步IO是指:IO的请求发出去之后,请求者一直在等待回复,当IO的数据回来到来之后,请求者就开始接受数据。阻塞的意思就是:IO请求发出去之后请求线程就停止在那里,一直等待数据到来。
非阻塞则是:IO请求发出去之后,会立刻收到回复,这个回复可能是IO可以立即进行,或者是无法进行IO的错误。所以非阻塞IO请求者必须一直调用那个API,一直到API返回可以进行IO的信号。
异步IO:IO请求发出之后,后台会建立一个进程,处理IO,当IO都处理完之后,把处理完的数据交给IO的请求者。
本文用Java socket实现阻塞和非阻塞IO(这里大部分内容都学习自千与的专栏,这是位大牛,居然hadoop源码分析写了19篇博客)。然后本文章的所有代码我都放在Github上了。
阻塞IO
阻塞IO比较简单,就是用普通的socket去写,因为没有什么太复杂的处理。建立一个socket,然后,获取它的inputstream和outputstream,然后进行读写操作。
Server端主要代码,handleSocket就是从socket里面读取数据,然后向client写数据:
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
socket = serverSocket.accept();
handleSocket(socket);
}
Client只是简单的发送一句消息:
socket = new Socket(host, port);
out = socket.getOutputStream();
out.write(data);
out.flush();
in = socket.getInputStream();
byte[] buffer = new byte[128];
int receivedBytes;
if((receivedBytes = in.read(buffer))!=-1){
System.out.println("Client: received msg from server: " + new String(buffer, 0, receivedBytes));
}
同时client5000个,使用了大概5s。然后还可以使用多线程Server,就是在每一个client到的时候分配一个线程来处理这个IO,理论上可以增加效率,但是似乎是因为每次处理时间太短,效果不明显。主要代码:
boolean flag = false;
int count = 0;
ServerSocket serverSocket = new ServerSocket(port);
Date start = null;
while (true) {
socket = serverSocket.accept();
if (!flag) {
start = new Date();
flag = true;
}
pool.execute(new RequestHandler(socket));
if(++count== threadCount){
flag = false;
Date end = new Date();
System.out.println(threadCount+" client requests spends: " + (end.getTime() -start.getTime()));
}
}
其中的pool是ExecutorService,提供线程池,然后RequestHandler是一个Runnable类,用来处理一个socket连接。简单讲来,就是把前面server处理socket的代码放到了这个handler里面。
NIO,非阻塞IO
我认定Java的NIO包实现的是同步非阻塞IO,也有人说不是,至少我这里这么认为。在server端,首先打开一个channel,然后向其中注册一个selector,这个selector会在channel中轮询注册的事件,然后根据事件的类型作出处理。一般事件的类型有Accept、read、write。
在Client端也可以是一样的注册,然后通过和server同样的处理方式处理事件(但是没有accept事件,因为只有server才能accept的)。但是我的例子里面只是简单的发送了一条消息。
Server的主要代码:
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel
.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(address);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
log.info("Server: socket server started!");
while (true) {
int nKeys = selector.select();
if (nKeys > 0) {
Set selectedKeys = selector.selectedKeys();
Iterator it = selectedKeys.iterator();
while (it.hasNext()) {
SelectionKey key = (SelectionKey) it.next();
if (key.isAcceptable()) {
log.info("Server: Selection key is acceptable");
handler.handleAccept(key);
} else if (key.isReadable()) {
log.info("Server: Selection key is readable");
handler.handleRead(key);
} else if (key.isWritable()) {
log.info("Server: Selection key is writable");
handler.handleWrite(key);
}
it.remove();
}
}
}
其中的handler就是处理每种类型的事件的类,举个Read的例子:
public void handleRead(SelectionKey key) throws IOException {
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
SocketChannel socketChannel = (SocketChannel) key
.channel();
while (true) {
int readBytes = socketChannel.read(byteBuffer);
if (readBytes > 0) {
log.info("Server: readBytes = " + readBytes);
log.info("Server: data = " + new String(byteBuffer.array(), 0, readBytes));
byteBuffer.flip();
socketChannel.write(byteBuffer);
break;
}
}
socketChannel.close();
}
Client就比较简单了,就是用channel直接发送了一句消息:
public void send(String data) {
try {
SocketChannel socketChannel = SocketChannel.open(inetSocketAddress);
socketChannel.configureBlocking(false);
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
socketChannel.write(ByteBuffer.wrap(data.getBytes()));
while (true) {
byteBuffer.clear();
int readBytes = socketChannel.read(byteBuffer);
if (readBytes > 0) {
byteBuffer.flip();
log.info("Client: readBytes = " + readBytes);
log.info("Client: data = " + byteBuffer.toString());
socketChannel.close();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
最后,这些Java的socket编程在实际工程中已经很少使用了,由于Unix的poll等功能的出现,select相比较之下,有点弱了。接下来可以考虑研究下。
NIO包的API介绍:
http://wufan0023.iteye.com/blog/198722
http://wufan0023.iteye.com/blog/198710
- 分享到:
This entry was posted in Java topic and tagged Java, socket by 柳浪闻莺. Bookmark the permalink.
Java Socket IO(BIO、NIO)的更多相关文章
- 深入分析JAVA IO(BIO、NIO、AIO)
IO的基本常识 1.同步 用户进程触发IO操作并等待或者轮询的去查看IO操作是否完成 2.异步 用户触发IO操作以后,可以干别的事,IO操作完成以后再通知当前线程继续处理 3.阻塞 当一个线程调用 r ...
- 【转】深入分析JAVA IO(BIO、NIO、AIO)
IO的基本常识 1.同步 用户进程触发IO操作并等待或者轮询的去查看IO操作是否完成 2.异步 用户触发IO操作以后,可以干别的事,IO操作完成以后再通知当前线程继续处理 3.阻塞 当一个线程调用 r ...
- JAVA SOCKET 通信总结 BIO、NIO、AIO ( NIO 2) 的区别和总结
1 同步 指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪 自己上街买衣服,自己亲自干这件事,别的事干不了.2 异步 异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已 ...
- Java网络通信方面,BIO、NIO、AIO、Netty
码云项目源码地址:https://gitee.com/ZhangShunHai/echo 教学视频地址:链接: https://pan.baidu.com/s/1knVlW7O8hZc8XgXm1dC ...
- Java IO 之 BIO、NIO、AIO
1.BIO.NIO.AIO解释 Java BIO : 同步并阻塞 (Blocking IO) 一个连接一个线程 即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不 ...
- tomcat并发优化之三种接收处理请求方式(BIO、NIO、APR)介绍
原文链接:http://blog.csdn.net/xyang81/article/details/51502766 Tomcat支持三种接收请求的处理方式:BIO.NIO.APR 1>.BIO ...
- (转)Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)
原文出自:http://blog.csdn.net/anxpp/article/details/51512200 1.BIO编程 1.1.传统的BIO编程 网络编程的基本模型是C/S模型,即两个进程间 ...
- Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)
本文会从传统的BIO到NIO再到AIO自浅至深介绍,并附上完整的代码讲解. 下面代码中会使用这样一个例子:客户端发送一段算式的字符串到服务器,服务器计算后返回结果到客户端. 代码的所有说明,都直接作为 ...
- Java 网络IO编程(BIO、NIO、AIO)
本概念 BIO编程 传统的BIO编程 代码示例: public class Server { final static int PROT = 8765; public static void main ...
随机推荐
- 面向对象OONo.3单元总结
一,JML语言 1)JML理论基础:JML是一类语言,用来描述一个方法或一个类的功能.以及这个类在实现这个功能时需要的条件.可能改变的全局变量.以及由于条件问题不能实现功能时这个方法或类的行为,具有明 ...
- 2019.05.26 周日--《阿里巴巴 Java 开发手册》精华摘要
一.写在开头 Java作为一个编程界最流行的语言之一,有着很强的生命力.代码的编写规范也是不容忽视的,今天,我就把自己阅读的国内的互联网巨头阿里巴巴的<阿里巴巴 Java 开发手册>一些精 ...
- Nginx正向代理代理http和https服务
Nginx正向代理代理http和https服务 1. 背景需求 通过Nginx正向代理,去访问外网.可实现局域网不能访问外网的能力,以及防止在上网行为上,留下访问痕迹. 2. 安装配置 2.1安装 w ...
- cocos2dx for lua 截屏功能
cocos2dx的utils类中包含截图功能,使用方法如下: cc.utils:captureScreen(function(successed,outputFile)--第一个参数是截图成功或者失败 ...
- NSOperation、NSOperationQueue
NSOperation.NSOperationQueue NSOperation 和 NSOperationQueue 配合使用也能实现多线程. NSOperation 继承于 NSObject,是一 ...
- 使用虚拟环境来管理python的包
1.背景 在开发python项目的过程中,我们会用到各种各样的包,我们使用pip来管理包,请看下图我们刚装好python解释器时已安装的包: 但是随着我们疯狂的使用pip install xxx后,系 ...
- java中常用的集合的一些区别 (2013-10-07-163写的日志迁移
java中的以下几大集合: List结构的集合类: ArrayListl类,LinkedList类,Vector类,stack类 Map结构的集合类: HashMap类,Hashtable类(此是以k ...
- Python头脑风暴2
今天想到了一个致富新途径:假如我在X东上班,我写个X宝爬虫,专门爬在X宝买奢侈品的土豪,然后我自己注册个X宝号,用脚本一个个加他们然后给他们发信息说我X东这还有比你更便宜更好的...不知道行不行啊(狗 ...
- LeetCode(173) Binary Search Tree Iterator
题目 Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the ...
- mac 安装composer的方法
打开命令后 cd /usr/local/bin 然后执行 curl -sS https://getcomposer.org/installer | php 接下来 sudo mv composer.p ...