总结下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 Javasocket by 柳浪闻莺. Bookmark the permalink.

Java Socket IO(BIO、NIO)的更多相关文章

  1. 深入分析JAVA IO(BIO、NIO、AIO)

    IO的基本常识 1.同步 用户进程触发IO操作并等待或者轮询的去查看IO操作是否完成 2.异步 用户触发IO操作以后,可以干别的事,IO操作完成以后再通知当前线程继续处理 3.阻塞 当一个线程调用 r ...

  2. 【转】深入分析JAVA IO(BIO、NIO、AIO)

    IO的基本常识 1.同步 用户进程触发IO操作并等待或者轮询的去查看IO操作是否完成 2.异步 用户触发IO操作以后,可以干别的事,IO操作完成以后再通知当前线程继续处理 3.阻塞 当一个线程调用 r ...

  3. JAVA SOCKET 通信总结 BIO、NIO、AIO ( NIO 2) 的区别和总结

    1 同步 指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪 自己上街买衣服,自己亲自干这件事,别的事干不了.2 异步 异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已 ...

  4. Java网络通信方面,BIO、NIO、AIO、Netty

    码云项目源码地址:https://gitee.com/ZhangShunHai/echo 教学视频地址:链接: https://pan.baidu.com/s/1knVlW7O8hZc8XgXm1dC ...

  5. Java IO 之 BIO、NIO、AIO

    1.BIO.NIO.AIO解释 Java BIO : 同步并阻塞 (Blocking IO) 一个连接一个线程 即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不 ...

  6. tomcat并发优化之三种接收处理请求方式(BIO、NIO、APR)介绍

    原文链接:http://blog.csdn.net/xyang81/article/details/51502766 Tomcat支持三种接收请求的处理方式:BIO.NIO.APR 1>.BIO ...

  7. (转)Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)

    原文出自:http://blog.csdn.net/anxpp/article/details/51512200 1.BIO编程 1.1.传统的BIO编程 网络编程的基本模型是C/S模型,即两个进程间 ...

  8. Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)

    本文会从传统的BIO到NIO再到AIO自浅至深介绍,并附上完整的代码讲解. 下面代码中会使用这样一个例子:客户端发送一段算式的字符串到服务器,服务器计算后返回结果到客户端. 代码的所有说明,都直接作为 ...

  9. Java 网络IO编程(BIO、NIO、AIO)

    本概念 BIO编程 传统的BIO编程 代码示例: public class Server { final static int PROT = 8765; public static void main ...

随机推荐

  1. kvm笔记

    1 virt-manager安装虚拟机无法使用键盘解决 今天远程用VNC登录服务器安装虚拟机,结果使用virt-manager安装虚拟机后在初始阶段无法使用键盘设置,这不雪崩了,后来来回试,找到了原因 ...

  2. 【离线 撤销并查集 线段树分治】bzoj1018: [SHOI2008]堵塞的交通traffic

    本题可化成更一般的问题:离线动态图询问连通性 当然可以利用它的特殊性质,采用在线线段树维护一些标记的方法 Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常 ...

  3. [51Nod] 1218 最长递增子序列 V2

    如何判断一个元素是否一定在LIS中?设f[i]为以ai结尾的LIS长度,g[i]为以ai开头的LIS长度,若f[i]+g[i]-1==总LIS,那么i就一定在LIS中出现 显然只出现一次的元素一定是必 ...

  4. Linux - NodeJS安装

    1> 去NodeJS官网 https://nodejs.org/en/ 或 中文网 http://nodejs.cn/download/ 拷贝相应版本的安装文件,如下图: 2> 执行 wg ...

  5. MySQL左右连接查询中的NULL的数据筛选问题

    这里使用左连接为例子,对于左连接是将左边表的数据显示,右边表中如果没有对应的数据则使用null填充. game表: game_type表: SELECT g.name,g.type_id,t.type ...

  6. 传智 Python基础班+就业班+课件 【最新完整无加密视频课程】

    点击了解更多Python课程>>> 传智 Python基础班+就业班+课件 [最新完整无加密视频课程] 直接课程目录 python基础 linux操作系统基础) 1-Linux以及命 ...

  7. Eclipse上进行java web项目的打包

    以下是一个基于maven搭建的Spring Boot项目的目录结构 版权声明:本文为博主原创文章,未经博主允许不得转载. 原文地址: https://www.cnblogs.com/poterliu/ ...

  8. python 程序小测试

    python 程序小测试 对之前写的程序做简单的小测试 ... # -*- encoding:utf-8 -*- ''' 对所写程序做简单的测试 @author: bpf ''' def GameOv ...

  9. 树莓派开发板入门学习笔记2:[转]树莓派系统在VM中能做什么

    问"树莓派系统在VM中能做什么"不如问"树莓派能做什么":(参考:树莓派实验室) 普通难度的DIY 较高难度的DIY 用树莓派打造一个家庭影院 给树莓派安装摄像 ...

  10. CF 510b Fox And Two Dots

    Fox Ciel is playing a mobile puzzle game called "Two Dots". The basic levels are played on ...