io->socket->应用tomcat(7.0版本Tomcat的底层是Socket编程)
nio->SocketChannel->tomcat(8.0版本)
tcp协议->socket-netty
socket(网络通信)
磁盘与IO基础知识:http://t.zoukankan.com/iwehdio-p-14248593.html
nio介绍:https://baijiahao.baidu.com/s?id=1709430016589717829&wfr=spider&for=pc
https://www.jb51.net/article/211036.htm
一.慨念
1.Buffer
ByteBuffer详解:https://blog.csdn.net/t000818/article/details/79023134
allocate方式
核心参数capacity:
核心参数 position:
核心参数limit:
allocateDirect方式
2.Channel
1.FileChannel file
2.SocketChannel与ServerSocketChannel TCP
3.DatagramChannel UDP
4.Pipe
3.Selector
一.nio比io快的原理
个人理解:
1、io是面向流的,字节流和字符流,其读与写是频繁与磁盘交互,是用户态和内核态频繁切换,也就是io是用户态,不能直接操作内核,需要操作系统调用内核来读写磁盘,切换本身就耗时;
nio是面向缓冲区的,使用内存映射,直接操作内存中数据(类似于c语言中allocateMemery等方法,这一点类似cas直接操作内存),避免了用户态和内核态的频繁奇切换
2、io是线程阻塞的,一个连接或者说一个线程读取,在没有数据之后进入阻塞,等待;
nio是线程非阻塞,其使用的buffer和channel(双向通道),当前通道没有数据读取时,可以切换到另一个通道(数据的来源或目的地)中;
3、io是一个线程一个连接
nio使用selector选择器,响应式处理客户端的请求,一个线程可以解决多个连接的数据处理;
二.nio使用
在io上使用
1.nio文件读写
2.io与nio实现大文件复制的效率对比:https://blog.csdn.net/zhangcongyi420/article/details/103099441
3.nio实现文件上传下载:https://blog.51cto.com/u_14693305/5529441
4.BIO、NIO、AIO按行读取文件汇总:https://blog.csdn.net/judyjie/article/details/86608283
在socket上使用
5.java nio简单示例:实现客户端与服务器一问一答:https://blog.csdn.net/qq_37855749/article/details/116190818
三.例子
1.nio文件读写例子
/**
* nio 使用缓冲区,非直接缓冲区读写文件
*/
public void test3() {
try (
FileInputStream fis = new FileInputStream("1.jpg");
FileOutputStream fos = new FileOutputStream("2.jpg");
FileChannel fisChannel = fis.getChannel();
FileChannel fosChannel = fos.getChannel();
){
// 分配指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocateDirect(1024);
// 将通道中的数据存取缓冲区
while (fisChannel.read(buf) != -1) {
// 读取信息
buf.flip();
fosChannel.write(buf);
buf.clear();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 使用nio读写文件 :使用直接缓冲区读写文件,速度快,不建议使用,占内存,适用于小文件
*/
public static void test4(String file) throws IOException {
// 读模式
FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
// StandardOpenOption.CREATE没有就创建,有就覆盖,StandardOpenOption.CREATE_NEW有就报错
FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
// 内存映射文件和ByteBuffer.allocateDirect(1024);直接获取缓冲区一模一样
// 缓存区目前在物理内存中,直接缓冲区只有ByteBuffer支持
MappedByteBuffer map = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer map2 = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
// 直接操作缓冲区
byte[] bs = new byte[map.limit()];
map.get(bs);
map2.put(bs);
}
/**
* 通道之间传输数据,直接缓冲区复制文件
*/
public void test5() throws IOException {
// 读模式
FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
// StandardOpenOption.CREATE没有就创建,有就覆盖,StandardOpenOption.CREATE_NEW有就报错
FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
// 从哪到哪去
inChannel.transferTo(0, inChannel.size(), outChannel);
outChannel.transferFrom(inChannel, 0, inChannel.size());
inChannel.close();
outChannel.close();
}
/**
* 分散与读取,将通道中的内容分散到缓冲区中
*/
public void test6() throws Exception {
// 分散读取
RandomAccessFile raf = new RandomAccessFile("1.txt", "rw");
// 获取通道
FileChannel channel = raf.getChannel();
// 分配指定大小缓冲区
ByteBuffer allocate = ByteBuffer.allocate(100);
ByteBuffer allocate2 = ByteBuffer.allocate(1000);
// 分散读取
ByteBuffer[] bio = { allocate, allocate2 };
channel.read(bio);
for (ByteBuffer byteBuffer : bio) {
// 改编读模式
byteBuffer.flip();
}
// 将缓冲区转换为数组,从第0个转换到limit
System.out.println(new String(bio[0].array(), 0, bio[0].limit()));
System.out.println("======================");
System.out.println(new String(bio[0].array(), 0, bio[1].limit()));
// 聚集写入
RandomAccessFile rsf = new RandomAccessFile("2.txt", "rw");
FileChannel channel2 = rsf.getChannel();
channel2.write(bio);
}
/**
* 使用nio读取文件所有内容
*/
public static String readByNIO(String file){
StringBuffer result = new StringBuffer();
//第一步 获取通道
try (
FileInputStream fis = new FileInputStream(file);
FileChannel channel=fis.getChannel();
){
//文件内容的大小
int size=(int) channel.size();
//第二步 指定缓冲区
ByteBuffer buffer=ByteBuffer.allocate(size);
//第三步 将通道中的数据读取到缓冲区中
while(channel.read(buffer)!=-1) {
Buffer bf= buffer.flip();
byte[] bt=buffer.array();
result.append(new String(bt,0,bt.length));
buffer.clear();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result.toString();
}
/**
* 利用NIO将内容输出到文件中
*/
public static void writeFileByNIO(String file){
try (
FileOutputStream fos = new FileOutputStream(file);
//第一步 获取一个通道
FileChannel fc = fos.getChannel();
){
//第二步 定义缓冲区
ByteBuffer buffer = ByteBuffer.allocate(10);
for(int i=0; i<100; i++) {
String aaa = new String("aaa"+i);
byte[] bytes = aaa.getBytes();
for(int m=0; m<bytes.length; m++) {
buffer.put(bytes[m]);
if(buffer.remaining()==0) {
buffer.flip();
//将内容写到缓冲区
fc.write(buffer);
//fos.flush();
buffer.clear();
}
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
四.io实现socket
Java 网络编程 TCP 传输文件:https://zhuanlan.zhihu.com/p/79377902
改进:服务端多线程处理业务逻辑: Socket 流传输的实现 —— 基于TCP协议:https://zhuanlan.zhihu.com/p/33103147
五.nio实现socket 多线程
https://blog.csdn.net/yiguang_820/article/details/126245942?spm=1001.2014.3001.5501
io和nio使用最大区别在网络通信方面,io是同步阻塞,nio是同步非阻塞
例子:https://blog.csdn.net/dhrtyuhrthfgdhtgfh/article/details/90271123
六.springboot实现socket
io、nio、netty:https://blog.csdn.net/smltq/article/details/103534704
七.springboot整合netty实现socket
Netty检查连接断开的几种方法(只用过第三种方法):https://www.cnblogs.com/alan6/p/11715722.html
八.websocket
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
springboot+websocket:https://blog.csdn.net/qq_18432653/article/details/109579829
springboot+netty实现websocket:
九:netty
1.官网示例:https://github.com/YeautyYE/netty-websocket-spring-boot-starter/blob/master/README_zh.md
例子:https://blog.csdn.net/qq_27248637/article/details/102552840
2.websocket可实现聊天系统
问题:
1.websocket连接1分钟后自动断开的解决方法:https://blog.csdn.net/rockstreet/article/details/113826562
WebSocket的心跳重连机制:https://blog.csdn.net/qq_33922980/article/details/102646295
十.问题:
1.请问 TCP、Socket、Servlet 、Tomcat 是如何通信的?https://www.zhihu.com/question/399406330
Tomcat 约等于 HTTP服务器(socket连接器) + Servlet容器
2.socket和servlet
socket是应用层与运输层之间的接口,一次连接在客户端和服务器分别有一个socket和server Socket,HTTP 报文经过socket接口进入运输层。
(1)Socket是最底层的通信机制
(2)HTTP是Socket之上的封装层,例如 HttpClient 等。
(3)Servlet是Java 对 HTTP的封装层,目的是为了更好的处理HTTP请求(包括参数)和HTTP响应,毕竟HTTP就分为请求和响应两大部分。
(4)Tomcat是Servlet容器。Servlet必须运行在容器之上。
Tomcat 实现了网络编程,通过servlet处理HTTP报文,再通过socket接口通信。因此我们只需编写经过封装了的servlet程序,容器通过反射等实现通信。
3.那么再来说说Socket和Tomcat的关系:https://www.cnblogs.com/zhangrj9/p/11678048.html
4.阻塞和非阻塞、同步和异步:https://baike.baidu.com/item/%E9%98%BB%E5%A1%9E%E5%92%8C%E9%9D%9E%E9%98%BB%E5%A1%9E/23734057?fr=aladdin
看完此链接后,同步异步在于是否需要等待结果返回;阻塞非阻塞在于当前线程在结果未返回之前是否可以做其他事情。
io、nio、tcp协议、socket、websocket、netty、tomcat
于 2022-08-10 15:54:35 首次发布