1.工作中使用IO流的操作
java的IO操作从方向上分为inputStream和outputStream。从单位上有字节流和字符流,字节流可以通过StreamReader转化为字符流,为了提高效率我们也用到了buffer流
( 以上介绍的流操作都是BIO流,项目中直接操作IO的业务场景 不是太多。但是我了解的很多分布式框架底层的通信都是使 用NIO流,NIO流最核心的组件就是Buffer、Chanel和 Selector了)
2.文件通常是由一连串的字节或者字符组成,组成文件的字节序列称为字节流,组成文件的字符序列称为字符流。根据流的方向分为输入流和输出流。(输入流是将文件或其它输入设备的数据加 载到内存的过程,输出流是将内存中的数据保存到文件或者其它输出设备的过程)
3.各种类型流的关系图片
4.BIO流的概述
同步阻塞,服务端实现模式为一个连接一个线程,即客户端有连接的请求时,服务器端就需要启动一个线程进行处理
实现方式:
采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端的连接,无客户端连接即阻塞。
可以通过多线程来支持多个客户端的连接
缺点:大量的客户端导致大量的线程产生,较大消耗。
改进办法:伪异步BIO
为了解决同步阻塞I/O面临的一个链路需要一个线程处理的问题,后端通过一个线程池来处理多个客户端的请求接入,形成客户端个数M,线程池最大线程数N的比例关系,通过
线程池可以灵活的调配线程资源,设置线程最大值,防止由于海量线程并发导致线程池资源耗尽
BIO代码实现
public class BIODemo01 {
public static void main(String[] args) {
//定义一个服务端
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(7777);
// 监听机制,当有新的连接那么需要创建一个线程
while (true){
Socket socket = serverSocket.accept();//阻塞的
//有连接了
new Thread(){
@Override
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
String str = "";
while (true){
if((str = in.readLine())==null) break;
System.out.println("服务器端接受到的数据是:"+ str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}catch (Exception e){
}finally {
//关闭相关资源
}
}
}
测试:
打开cmd命令窗口,使用:telnet 127.0.0.1 7777 然后发送文字进行测试
伪BIO代码实现
public class BIODemo02 {
public static void main(String[] args) throws Exception {
ExecutorService pool = Executors.newCachedThreadPool();//创建线程池
ServerSocket serverSocket = new ServerSocket(8888);//端口号
while (true){
Socket socket = serverSocket.accept(); //阻塞
pool.execute(new Runnable() {
@Override
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
String str = "";
while (true){
if((str = in.readLine())==null) break;
System.out.println("服务器端接受到的数据是:"+ str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
}
测试同上,
NIO介绍
概述:同步非阻塞,服务器实现模式一个线程处理多个请求
原理图:
三大特点:Selector, Channle,buffer
Selector:是一个抽象类定义了一些方法,有一个具体的实现SelectorImpl。本质是一个选择器,可以检测一到多个NIO通道,并能够知晓通道是否做好了进行读写的准备。这样,一个线程可以 管理多个Channel,从而管理多个网络连接。
Channel:和流一样都是在读写之间进行操作的通道,不同的是,Channel是双向的,从原理图中也可以看出来,可读可写,而且可以异步进行读写,是基于buffer进行操作的
分类:
FileChannel:主要用于对本地文件进行IO操作
DatagramChannel:用于UDP数据读写
SocketChannel:用于TCP数据读写,客户端实现
ServerSocketChannel:用于TCP数据读写,服务器实现
tcp和upd都是传输层的协议
(TCP与UDP区别总结:
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保 证可靠交付
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的 UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用 很有用,如IP电话,实时视频会议等)
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
buffer :
AIO简介
概述:异步非阻塞,AIO引入异步通道采用的是Proactor模式,简化了程序编写有效的请求才启动线程
如下代码展示:
package net.csdn.se.nio;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NIODemo {
public static void main(String[] args) throws Exception{
FileInputStream fileInputStream = new FileInputStream("D:\\1.txt");
FileChannel inChanel = fileInputStream.getChannel();
FileOutputStream fileOutputStream = new FileOutputStream("D:\\2.txt");
FileChannel outChannel = fileOutputStream.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
// 将文件1内容读到buffer中并写到文件2中
while (true){
byteBuffer.clear();
int read = inChanel.read(byteBuffer);
if(read == -1){
break;
}
//将buffer内容写到 2
byteBuffer.flip();
outChannel.write(byteBuffer);
}
}
}