总结下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. CentOS安装RabbitMQ步骤

    1.安装gcc yum install gcc 安装 ncurses-devel yum install ncurses-devel 2.安装erlang 下载安装包 http://www.erlan ...

  2. MFC中获得各种指针概述(个人觉得是很重要的重点)

    前言:这学期学习MFC(有点过时的东西),上课时,老师讲到获取当前活动指针,获取视图指针,文档指针,文档模板指针等(已晕) 后来下来真正写代码的时候发现这些几乎都是需要用到的东西,所以特此记录下,让自 ...

  3. STL容器之Array[转]

    转自https://blog.csdn.net/sin_geek/article/details/51067874 作者 Sin_Geek 简介 array在头文件<array> 中定义 ...

  4. 解析Vue.js中的computed工作原理

    我们通过实现一个简单版的和Vue中computed具有相同功能的函数来了解computed是如何工作的.写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下.如有不足之处,欢迎批评指 ...

  5. Python基础——赋值机制

    使用id()函数用于获取对象的内存地址. 使用is来判断是不是指向同一个内存. 把一个对象赋值给另一个对象,两个对象都指向同一个内存地址. test=1000 test1=test id(test) ...

  6. 使用TensorFlow的卷积神经网络识别手写数字(3)-识别篇

    from PIL import Image import numpy as np import tensorflow as tf import time bShowAccuracy = True # ...

  7. python能干什么?

    python能干什么? 网络爬虫 爬虫,指的是从互联网采集数据的程序脚本 . 爬天爬地爬空气 ,无聊的时候爬一爬吃鸡数据.b站评论,能得出很多有意思的结论.知乎有个很有意思的问题——"利用爬 ...

  8. 03009_HttpServletResponse

    1.HttpServletResponse概述 (1)我们在创建Servlet时会覆盖service()方法,或doGet()/doPost(),这些方法都有两个参数,一个为代表请求的request和 ...

  9. Angularjs中的事件广播 —全面解析$broadcast,$emit,$on

    Angularjs中不同作用域之间可以通过组合使用$broadcast,$emit,$on的事件广播机制来进行通信 介绍: $broadcast的作用是将事件从父级作用域传播至子级作用域,包括自己.格 ...

  10. webdriver高级应用- 改变一个页面对象的属性值

    适用于一些无法操作的元素,可以直接改他的属性从而操作,代码如下: #encoding=utf-8 from selenium import webdriver import unittest impo ...