java的I/O操做类在包java.io下,大体分红4组:前端
全部文件的存储都是字节(byte)的储存,在磁盘上保留的并非文件的字符而是先把字符编码成字节,再存储这些字节到磁盘。在读取文件时,也是一个字节一个字节读取。java
字节流能够用于任何类型的对象,包括二进制对象;而字符流只能处理字符或者字符串linux
字节流是最基本的,全部的InputStrem和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的。ios
但实际中不少的数据是文本,又提出了字符流的概念,它是按虚拟机的encode来处理,也就是要进行字符集的转化。程序员
字符和字节流这两个之间经过 InputStreamReader,OutputStreamWriter来关联,其实是经过byte[]和String来关联 在实际开发中出现的汉字问题实际上都是在字符流和字节流之间转化不统一而形成的。web
2.1 java的I/O类库的基本架构数据库
2.1.1 基于字节的I/O操做接口后端
InputStream和OutputStream设计模式
inputStream的read()返回int:0到255范围内的int字节值。若是到达末尾而没有可用的字节,返回-1.所以不能用于0-255数组
来表示的值就得用字符流来读取。
2.1.2 基于字符的I/O操做接口
无论是磁盘仍是网络传输,最小的存储单元是字节,而不是字符,因此I/O操做的都是字节而不是字符。
可是为何有操做字符的I/O接口呢?这是由于程序中常常操做的数据都是字符形式的,为了操做方便固然要提供一个直接写字符的I/O接口。
从字符到字节必须通过编码转换,而编码又耗时,编码还容易出现乱码。
Writer类提供了一个抽象方法write(char cbuf[], int off, int len).
读字符的接口是int read(char cbuf[], int off, in len): 返回的int:做为整数读取的字符(16位,2个字节),范围是0到65535,若是已经到流的末尾,
则返回-1
2.1.3 字节与字符的转化接口
数据持久化或网络传输都是以字节进行的,因此必需要有从字符到字节或从字节到字符的转化。
InputStreamReader类:从字节到字符转化的桥梁, 从inputStream到reader的过程是指定编码字符集,不然将采用操做系统默认的字符集,极可能出现乱码问题。
StreamDecoder正是完成从字节到字符的解码的实现类。
补充:IO部分介绍不详细,此处补充一些IO的知识
补充1:若是须要建立文件须要如下操做:判断映射的文件是否真实存在fie.existes() ,为true就存在,不然不存在。
若是文件不存在要调用file.createdNewFile() 建立真实文件,可是,这个方法只是会建立文件自己,若是文件的目录不存在,则不会建立目录。因此须要对父文件存在与否左判断。
File parent = file.getParentFile() // 获取父文件
if(!parent.exists()) parent.mkdirs(); // 建立父文件夹。
补充二:FileInputStream是有缓冲区的,因此用完以后必须关闭,不然可能致使内存占满,数据丢失。
int count = 0; InputStream streamReder = null; try { streamReder = new FileInputStream(new File("folder1/fsdfsdf/fsdffd/fileName4.txt")); while(streamReder.read() != -1) // 每次读一个字节,返回的是字节的int表示0 ~ 255 { count++; } System.out.println("---长度是: "+count+" 字节");
补充三:
OutputStream out=new FileOutputStream("D:/David/Java/java 高级进阶/files/tiger2.jpg");
out.write(buffer, 0, numberRead); //不然会自动被填充0
补充四:ObjectInputStream和ObjectOutputStream
可是要实现这种功能,被读取和写入的类必须实现Serializable接口
补充五:字符流
FileWriter是被修饰者
BufferedWriter 是修饰者
BufferedWriter bw = new BufferedWriter(new FileWriter("file name"));
上面这个BufferedWriter加了一个缓冲,缓冲写满后再将数据写入硬盘,这样极大的提升性能。必需要有bw.flush()这句,若是没有,而仅有writer.close(),会报异常。
若是单独使用FileWriter也能够,每写一个数据,硬盘就有一个写动做,性能差。
OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(f)); BufferedWriter writer = new BufferedWriter(write); writer.write(content); writer.flush(); write.close(); writer.close();
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
FileReader fk=new FileReader("f:/23.txt"); //从F盘读取一个文件fk接收
BufferedReader bk=new BufferedReader(fk); //生成一个容器bk把文件fk内容装进去,这样bk的内容就是原文件23.txt的内容了
从定义上看可能会让你感到困惑,这里解释一下:输入输出是相对于内存设备而言的
补充六:
没有明确指定须要使用的字符编码方案时,Java程序经过“java.nio.charset.Charset.defaultCharset().name()”语句来获取默认的字符编码方案,该语句返回的值跟运行Java程序的操做系统的设置有关,在有些操做系统上,该语句返回值多是UTF-8;在有些操做系统上,该语句返回值多是GBK;在有些操做系统上,该语句返回值多是除了UTF-8和GBK之外的其余字符编码方案。这样子,程序的可移植性大大下降。
编码只发生在JVM和底层操做系统(以及网络传输)之间进行数据传输时,若是程序中没有IO操做,那么全部的String和Char都以unicode编码。当从磁盘读取文件或者往磁盘写入文件时使用的编码要一致,也就是编码和解码使用的字符集要同样才不会出现乱码
Unicode :又称万国码,顾名思义,unicode中收录了世界各国语言,用以解决传统编码的局限性。它为每种语言中的每一个字符设定了统一而且惟一的二进制编码,以知足跨语言、跨平台进行文本转换、处理的要求。
UTF-8:(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码.
一、不一样编码表示一个字符所占用字节是不相同的,其中ASCII码占一个字节,GB23十二、GBK、unicode都用2字节表示一个字符。而UTF-8是可变长的,英文字母用1字节,汉字用3字节表示。
二、同一个字符在不一样编码表中的位置也是不一样的,好比汉字‘中’在GBK中是D6D0,而在unicode中是4E2D。也就致使了当汉字的解码方式和编码方式不一样时会产生乱码。
每一个Java程序员都应该记住,Java使用的是Unicode编码。全部的字符在JVM中(内存中)只有一个存在形式就是Unicode。因此一个char占用2字节。
Java的IO体系中面向字符的IO类只有Reader和Writer,可是最经常使用的FileReader和FileWriter类不支持自定义编码类型,只能使用系统默认编码。这样一来,读写文件的编码就必定一致了,也就减小了乱码的可能性。我的理解,这么作多是强制帮助用户完成编码一致,下降乱码率。若是要自定义编码,要用其父类InputStreamRreader和OutputStreamWriter
补充七: JAVA中几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是什么?
字节流和字符流。
字节流和字符流区别?
计算机中的一切最终都是二进制的字节形式存在。对于“中国”这些字符,首先要获得其对应的字节,而后将字节写入到输出流。读取时,首先读到的是字节,但是咱们要把它显示为字符,咱们须要将字节转换成字符。因为这样的需求很普遍,人家专门提供了字符流的包装类。
底层设备永远只接受字节数据,有时候要写字符串到底层设备,须要将字符串转成字节再进行写入。字符流是字节流的包装,字符流则是直接接受字符串,它内部将串转成字节,再写入底层设备,这为咱们向IO设别写入或读取字符串提供了一点点方便
什么是JAVA序列化?如何实现序列化?
补充八:Unicode 和 UTF-8区别
String newStr = new String(oldStr.getBytes(), "UTF-8");
java中的String类是按照unicode进行编码的,当使用String(byte[] bytes, String encoding)构造字符串时,encoding所指的是bytes中的数据是按照那种方式编码的,而不是最后产生的String是什么编码方式,换句话说,是让系统把bytes中的数据由encoding编码方式转换成unicode编码。若是不指明,bytes的编码方式将由jdk根据操做系统决定。
// 打开文件时,指定编码方式。
InputStreamReader read = new InputStreamReader (new FileInputStream(f),"UTF-8");
FileReader读取文件的过程当中,FileReader继承了InputStreamReader,但并无实现父类中带字符集参数的构造函数,因此FileReader只能按系统默认的字符集来解码。
用InputStreamReader代替FileReader,InputStreamReader isr=new InputStreamReader(new FileInputStream(fileName),"UTF-8");这样读取文件就会直接用UTF-8解码,不用再作编码转换。
// 指定编码方式 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(saveFilename),"GB2312")); PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(saveFilename),"GB2312")));
补充九:
发现:全部的字节相关的都是以Stream为结尾; 全部的字符相关的都是以writer/reader为结尾。
以字节为导向的stream------InputStream/OutputStream。
InputStream 和 OutputStream是两个abstact类,对于字节为导向的stream都扩展这两个鸡肋(基类^_^);
--InputStream
ByteArrayInputStream - 把内存中的一个缓冲区做为InputStream使用。
StringBufferInputStream - 把一个String对象做为InputStream(不推荐使用) .
FileInputStream -- 把一个文件做为InputStream,实现对文件的读取操做
PipedInputStream - 实现了pipe的概念,主要在线程中使用. 管道输入流是指一个通信管道的接收端。
一个线程经过管道输出流发送数据,而另外一个线程经过管道输入流读取数据,
这样可实现两个线程间的通信。
SequenceInputStream - 把多个InputStream合并为一个InputStream .“序列输入流”类容许应用程序把几个输入流连续地合并起来,
而且使它们像单个输入流同样出现。每一个输入流依次被读取,直到到达该流的末尾。
而后“序列输入流”类关闭这个流并自动地切换到下一个输入流。
--OutputSteam
ByteArrayOutputStream - 把信息存入内存中的一个缓冲区中.该类实现一个以字节数组形式写入数据的输出流。
FileOutputStream:文件输出流是向 File 或 FileDescriptor 输出数据的一个输出流。
PipedOutputStream:管道输出流是指一个通信管道的发送端。 一个线程经过管道输出流发送数据,
而另外一个线程经过管道输入流读取数据,这样可实现两个线程间的通信。
以字符为导向的stream Reader/Writer
以Unicode字符为导向的stream,表示以Unicode字符为单位从stream中读取或往stream 中写入信息。 Reader/Writer 为abstact类 以Unicode字符为导向的stream包括下面几种类型:
-- Reader
1: CharArrayReader:与ByteArrayInputStream对应
2: StringReader:与StringBufferInputStream对应
3: FileReader: 与FileInputStream对应
4: PipedReader: 与PipedInputStream对应
-- Writer:
1) CharArrayWrite:与ByteArrayOutputStream对应
2) StringWrite:无与之对应的以字节为导向的stream
3) FileWrite:与FileOutputStream对应
4) PipedWrite:与PipedOutputStream对应
补充十:字符流和字节流之间转
InputStreamReader和OutputStreamReader:把一个以字节为导向的stream转换成一个以字符为导向的stream。
一个 InputStreamReader 类是从字节流到字符流的桥梁:它读入字节,并根据指定的编码方式,将之转换为字符流。
使用的编码方式可能由名称指定,或平台可接受的缺省编码方式。
InputStreamReader 的 read() 方法之一的每次调用,可能促使从基本字节输入流中读取一个或多个字节。
为了达到更高效率,考虑用 BufferedReader 封装 InputStreamReader,
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
InputStreamReader(InputStream) 用缺省的字符编码方式,建立一个 InputStreamReader。
InputStreamReader(InputStream, String) 用已命名的字符编码方式,建立一个 InputStreamReader。
OutputStreamWriter 将多个字符写入到一个输出流,根据指定的字符编码将多个字符转换为字节。
每一个 OutputStreamWriter 合并它本身的 CharToByteConverter, 于是是从字符流到字节流的桥梁。
补充十一:Java IO的通常使用原则
1、按数据来源(去向)分类:
一、是文件: FileInputStream, FileOutputStream, FileReader, FileWriter
二、是byte[]:ByteArrayInputStream, ByteArrayOutputStream
三、是Char[]: CharArrayReader, CharArrayWriter
四、是String: StringBufferInputStream(不推荐), StringReader, StringWriter
五、网络数据流:InputStream, OutputStream, Reader, Writer
2、按是否格式化输出分:
一、要格式化输出:PrintStream, PrintWriter
3、按是否要缓冲分:
一、要缓冲:BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter
4、按数据格式分:
一、二进制格式(只要不能肯定是纯文本的): InputStream, OutputStream及其全部带Stream结束的子类
二、纯文本格式(含纯英文与汉字或其余编码方式);Reader, Writer及其全部带Reader, Writer的子类
5、按输入输出分:
一、输入:Reader, InputStream类型的子类
二、输出:Writer, OutputStream类型的子类
6、特殊须要:
一、从Stream到Reader,Writer的转换类:InputStreamReader, OutputStreamWriter
二、对象输入输出:ObjectInputStream, ObjectOutputStream
三、进程间通讯:PipeInputStream, PipeOutputStream, PipeReader, PipeWriter
四、合并输入:SequenceInputStream
五、更特殊的须要:PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader
补充十二:几个经常使用类的用法
FileInputStream :在java中,可使用InputStream对文件进行读取,就是字节流的输入。
创建合适大小的byte数组,若是已知输入流的大小
File f = new File("E:"+File.separator+"java2"+File.separator+"StreamDemo"+File.separator+"test.txt"); InputStream in = new FileInputStream(f); byte b[]=new byte[(int)f.length()]; //建立合适文件大小的数组 in.read(b); //读取文件中的内容到b[]数组 in.close();
若是不知输入流的大小,则确定须要创建一个很大的byte数组,那么byte中极可能有空的内容,那么如何正确合适的将byte数组的中的内容输出:
File f = new File("E:"+File.separator+"java2"+File.separator+"StreamDemo"+File.separator+"test.txt"); InputStream in = new FileInputStream(f); byte b[] = new byte[1024]; int len = 0; int temp=0; //全部读取的内容都使用temp接收 while((temp=in.read())!=-1){ //当没有读取完时,继续读取 b[len]=(byte)temp; len++; } in.close();
FileOutputStream:
try{ // 构造一个要写的数据: byte[] data = "这个例子测试文件写".getBytes("GB2312"); FileOutputStream fo = new FileOutputStream("MyOut1.data"); fo.write(data); //fo.flush(); //若是OutputStream 的实现使用了缓存,这个方法用于清空缓存里的数据,并通知底层去进行实际的写操做 // FileOutputStream 没有使用缓存,所以这个方法调用与否在这个例子的运行结果没有影响。 fo.close(); }catch(Exception e) { e.printStackTrace(); }
BufferedInputStream是带缓冲区的输入流,默认缓冲区大小是8M,可以减小访问磁盘的次数,提升文件读取性能;BufferedOutputStream是带缓冲区的输出流,可以提升文件的写入效率。BufferedInputStream与BufferedOutputStream分别是FilterInputStream类和FilterOutputStream类的子类,实现了装饰设计模式。
OutputStream out = 38 new BufferedOutputStream( //是一种装饰模式 39 new FileOutputStream(file), 16); 40 41 // 将ArrayLetters数组的前10个字节写入到输出流中 42 out.write(ArrayLetters, 0, 10); 43 // 将“换行符\n”写入到输出流中 44 out.write('\n'); 45 46 // TODO! 47 //out.flush(); 51 out.close();
字符流:可是最经常使用的FileReader和FileWriter类不支持自定义编码类型,只能使用系统默认编码。这样一来,读写文件的编码就必定一致了,也就减小了乱码的可能性。我的理解,这么作多是强制帮助用户完成编码一致,下降乱码率。若是要自定义编码,要用其父类InputStreamRreader和OutputStreamWriter
// 声明一个File对象 File file = new File("hellowolrd.txt"); // 声明一个Write对象 Writer writer = null; // 经过FileWriter类来实例化Writer类的对象并以追加的形式写入 writer = new FileWriter(file, true); // 声明一个要写入的字符串 String str = "字符串形式写入Helloworld"; // 写入文本文件中 writer.write(str); // 刷新 writer.flush(); // 关闭字符输出流 writer.close(); // 声明一个File对象 File file = new File("hellowolrd.txt"); // 声明一个Reader类的对象 Reader reader = null; // 经过FileReader子类来实例化Reader对象 reader = new FileReader(file); // 声明一个字符数组 char[] c = new char[1024]; // // 将内容输出 // int len = reader.read(c); //循环方式一个一个读 int len=0; int temp=0; while((temp=reader.read())!=-1){ c[len]=(char)temp; len++; } // 关闭输入流 reader.close();
字符流读取、写入文件:
package ioTest; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.util.Scanner; public class CharRWStreamTest01 { public static void main(String[] args) { File file=new File("Text.txt"); File file2=new File("Text1.txt"); try { InputStream fis=new FileInputStream(file); // 定义字节流 InputStreamReader isr=new InputStreamReader(fis, "utf-8"); // 用字节流做为字符流的输入,可是要指定编码方式
这里InputStreamReader是由字节流到字符流的桥梁
BufferedReader br=new BufferedReader(isr); // 装饰模式 单缓存 OutputStream os=new FileOutputStream(file2,false); OutputStreamWriter osw=new OutputStreamWriter(os, "utf-8"); BufferedWriter bw=new BufferedWriter(osw); String ss; while((ss=br.readLine())!=null){ bw.write(ss); bw.write("\n"); } bw.flush(); br.close(); isr.close(); fis.close(); bw.close(); osw.close(); os.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
2.2 磁盘I/O工做机制
2.2.1 几种访问文件的方式
读取和写入文件IO,都调用OS提供的接口,磁盘由OS管理,应用程序要访问物理设备只能经过系统调用的方式来工做。读和写分别对应read() 和 write()。 而系统调用就涉及到内核空间地址和用户空间地址切换的问题,这是OS为了保护系统安全,把用户程序空间和内核空间隔离形成的。虽然保证了安全,可是必然存在数据须要从内核空间向用户空间复制的问题。
磁盘I/O操耗时,数据从磁盘复制到内核空间,再复制到用户空间,很是缓慢。OS为了加速I/O操做,在内核空间使用缓存机制,将从磁盘读取的文件按照必定的组织方式缓存,若是用户程序访问的是同一段磁盘地址的空间数据,那么OS将从内核缓存中直接取出返回给用户程序,减小I/O响应时间。
1 标准访问文件的方式
读和写都是针对内核的高速缓存。
2 直接I/O的方式
直接访问磁盘数据。如在数据库管理系统中,由应用程序控制哪些热点数据须要缓存,而不是OS。对热点数据能够进行预加载。
3 同步访问文件的方式
数据的读取和写入是同步的,与标准文件的访问方式不一样的是 只有数据被成功写到磁盘时才返回给应用程序成功标志。
4 异步访问文件的方式
5 内存映射的方式
2.2.2 Java 访问磁盘文件
如何将数据持久化到物理磁盘?
2.2.3 Java 序列化技术
将一个对象转化成一串二进制表示的字节数组,经过保存和转义这些字节数据来达到持久化的目的。
须要持久化一个对象,对象必须继承java.io.Serializable接口。
反序列化是相反的过程,将字节数组再从新构形成对象。反序列化时,必须有原始类做为模板,才能将对象还原。
序列化总结:
SerialVersionUID的做用:
简单来讲,Java的序列化机制是经过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,若是相同就认为是一致的,能够进行反序列化,不然就会出现序列化版本不一致的异常。(InvalidCastException)
2.3 网络I/O工做机制
2.3.1 TCP状态转化
(1) CLOSED状态
(2) Listen:Server端在等待链接的状态,Server为此要调用socket, bind, listen函数,进入这个状态。这称为应用程序被打开(等待客户端来连
接。)
(3) SYN-SENT: 有客户端要创建链接,通过三次握手创建。
(4) 关闭的时候:四次握手关闭。
2.3.2 影响网络传输的因素
网络带宽 、 传输距离、 TCP阻塞控制(TCP缓冲区大小)
2.3.3 Java Socket的工做机制
socket底层用的TCP/UDP协议。 socket经过绑定端口号,能够惟一肯定一个主机上应用程序的通讯链路
2.3.4 创建通讯链路
当客户端要与服务器端通讯时,客户端首先建立一个Socket实例,OS为这个socket建立一个没有使用过的本地端口号,并建立一个包含本地地址、远程地址和端口号的套接字,在socket构造函数正确返回以前,要进行TCP三次握手,握手完成后,socket实例对象被建立完成。
服务器端将建立一个ServerSocket实例,建立ServerSocket比较简单,只要指定的端口号没有被占用,通常都成功(同时会bind指定端口号,开始listen)。以后调用accept()方法时, 进入阻塞状态,等待客户端请求。当有新的请求到来时,将为这个链接创建一个新的套接字数据结构,该套接字数据结构包含地址和端口信息。注意:这时服务端与之对应的socket实例并无完成建立,要等到3次握手完成后,这个服务器端的socket才会返回。
2.3.5 数据传输
当链接建立完后,服务端和客户端都会拥有一个socket实例,每一个socket实例都有一个inputstreamf和outputstream, 用这两个对象交换数据。
网路传输的是字节流,当建立socket对象时,OS会为inputstream和outputstream分配缓冲区,数据读写经过这个缓冲区来完成的。
2.4 NIO的工做方式
对一个文件描述符指定的文件或设备, 有两种工做方式: 阻塞 与非阻塞 。所谓阻塞方式的意思是指, 当试图对该文件描述符进行读写时, 若是当时没有东西可读,或者暂时不可写, 程序就进入等待 状态, 直到有东西可读或者可写为止。而对于非阻塞状态, 若是没有东西可读, 或者不可写, 读写函数立刻返回, 而不会等待
2.4.1 BIO带来的挑战
BIO就是阻塞式I/O,不管是磁盘I/O仍是网络I/O,数据在写入OutputStream或者从InputStream读取时均可能会阻塞,一旦有阻塞,线程会失去CPU的使用权,这在当前大规模访问量和有性能要求的状况下是不能接受的。虽然当前网络I/O有一些解决办法,如一个客户端对应一个处理线程,出现阻塞时只是影响一个线程,不影响其余线程,还有为了减小系统线程的开销,采用线程池的办法减小线程建立和回收的成本。
可是在一些场景下仍然是没法解决的,好比一些须要大量HTTP长链接的状况,像淘宝如今使用的Web旺旺,服务端须要同时保持几百万HTTP链接,并非每时每刻这些链接都在传输数据,在这种状况下不可能建立那么多的线程保持链接。
就算线程数量不是问题,也存在以下问题:好比想给一些客户更高的优先级时,很难经过设计线程的优先级来完成;另外每一个客户端的请求在服务端可能须要访问一些竞争资源,由于客户端在不一样的线程,所以须要同步。
2.4.2 NIO的工做机制
2.4.3 Buffer的工做方式
2.4.4 NIO的数据访问方式
1.FileChannel.transferXXX
2. FileChannel.map
2.5 I/O调优
2.5.1 磁盘I/O优化
1. 性能检测
iostat : linux 下查看 iO的一些参数,I/O wait参数不该该操过25%。
iops: 每秒IO的读写次数。 是磁盘的性能指标。
raid: 磁盘冗余阵列。
2. 提高I/O性能
增长缓存,减小磁盘访问次数;
优化磁盘管理系统,设计最优的磁盘方式策略,以及磁盘的寻址策略,这是在底层OS层面考虑的;
设计合理的磁盘存储数据块,以及访问这些数据块的策略,这是从应用层面考虑。例如 咱们能够给存放的数据设计索引,经过寻址索引加快和减小磁盘的访问量,还能够采用异步和非 阻塞的方式加快磁盘的访问速度(具体方法好比,给数据库建索引,减小IO; NIO技术);
应用合理的RAID策略提高磁盘IO;
2.5.2 TCP网络参数调优
增大端口数目, 减小TIME_WAIT(能够快速释放请求) , 除此以外,还可让TCP复用等。
echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range设置向外链接可用端口范围 表示可使用的端口为65535-1024个(0~1024为受保护的)
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse 设置time_wait链接重用 默认0
echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle 设置快速回收time_wait链接 默认0
echo 180000 > /proc/sys/net/ipv4/tcp_max_tw_buckets 设置最大time_wait链接长度 默认262144
echo 1 > /proc/sys/net/ipv4/tcp_timestamps 设置是否启用比超时重发更精确的方法来启用对RTT的计算 默认0
echo 1 > /proc/sys/net/ipv4/tcp_window_scaling 设置TCP/IP会话的滑动窗口大小是否可变 默认1
echo 20000 > /proc/sys/net/ipv4/tcp_max_syn_backlog 设置最大处于等待客户端没有应答的链接数 默认2048
echo 15 > /proc/sys/net/ipv4/tcp_fin_timeout 设置FIN-WAIT状态等待回收时间 默认60
echo "4096 87380 16777216" > /proc/sys/net/ipv4/tcp_rmem 设置最大TCP数据发送缓冲大小,分别为最小、默认和最大值 默认4096 87380 4194304
echo "4096 65536 16777216" > /proc/sys/net/ipv4/tcp_wmem 设置最大TCP数据 接受缓冲大小,分别为最小、默认和最大值 默认4096 87380 4194304
echo 10000 > /proc/sys/net/core/somaxconn 设置每个处于监听状态的端口的监听队列的长度 默认128
echo 10000 > /proc/sys/net/core/netdev_max_backlog 设置最大等待cpu处理的包的数目 默认1000
echo 16777216 > /proc/sys/net/core/rmem_max 设置最大的系统套接字数据接受缓冲大小 默认124928
echo 262144 > /proc/sys/net/core/rmem_default 设置默认的系统套接字数据接受缓冲大小 默认124928
echo 16777216 > /proc/sys/net/core/wmem_max 设置最大的系统套接字数据发送缓冲大小 默认124928
echo 262144 > /proc/sys/net/core/wmem_default 设置默认的系统套接字数据发送缓冲大小 默认124928
echo 2000000 > /proc/sys/fs/file-max 设置最大打开文件数 默认385583
结合ab命令来压测机器优化网络
设置完记得保存
2.5.3 网络I/O优化
减小网络交互的次数:减小交互次数一般是在网络两端设置缓存,如Oracle的JDBC驱动程序就提供了对SQL结果的缓存,有效减小对数据库的访问。
还有一招,合并访问请求,好比查十回,每次查一个;也能够一次查10个;
访问的静态资源好比JS,CSS,可已经多个JS文件名称合并在一个HTTP请求中,发送web后端,后端根据URL 把JS文件打包一并返回给前端;
减小网络传输数据量的大小:数据压缩在传输;
尽可能经过读取协议头来获取有用信息,尽可能避免读取通讯数据body来得到须要的信息。
尽可能减小编码:减小字节和字符的转。
1. 同步与异步: 异步没法保证依赖,须要在可靠性和性能之间作平衡(作五星的时候,遇到过这个问题,加购物车,扣库存。)
2. 阻塞与非阻塞:主要从CPU消耗上来讲的,阻塞就是CPU停下来等待一个慢的操做;非阻塞就是慢操做执行时,CPU去作其余事;
非阻塞的方式虽然提升CPU利用率 可是线程切换增长;
3. 两种方式的组合:
2.6 设计模式解析之适配器模式
2.6.1 适配器模式的结构
2.6.2 Java I/O中的适配器模式
2.7 设计模式之装饰器模式
2.7.1 装饰器模式的结构
2.7.2 Java I/O中的装饰器模式
2.8 适配器模式与装饰器模式的区别