IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> NIO和BIO以及传统IO -> 正文阅读

[系统运维]NIO和BIO以及传统IO

首先明白这三个概念

1.NIO是非阻塞.基于网络的IO,即从网络上传过来的数据读取

2.BIO是阻塞.基于网络的IO,同上

3.传统IO,传统IO是和硬盘打交道,即读写硬盘,和网络没有关系

下文描述的是基于网络的NIO和BIO,耐心看完,前面是对网络的阐述,只有明白网络才能理解IO

1.计算机体系

image-20210722224416023

在linux系统中,一切皆文件,例如:摄像头,打印机,将他们两个抽象成文件,就是读取和输出文件

文件描述符: 在linux没有面向对象的概念,把一切抽象成文件了,当想操作一个输入输出设备,Socket等,连接文件以后,就有一个数字代表它,叫文件描述符,就像面向对象的引用变量一样

使用虚拟机查看系统调用

ubuntu中man的手册默认没有装。
?
第一步,打开虚拟机,打开超级终端
?
第二步,输入下面命令,一定要在联网的情况下,要不安装包下载不下来
?
用下面几条命令就行了:
?
#sudoapt-get install manpages #sudo apt-get install manpages-de #sudo apt-get install manpages-de-dev #sudo apt-get install manpages-dev
?
第三步,没有错误提示的话,就可以使用man了
?
Linux 的man手册共有以下几个章节:
?
1、Standard commands (标准命令)2、System calls (系统调用函数)3、Libraryfunctions (库函数)4、Specialdevices (设备说明)5、File formats (文件格式)6、Games andtoys (游戏和娱乐)7、Miscellaneous(杂项)8、AdministrativeCommands (管理员命令)
?

使用指令: man 2 read 查看关于read的系统调用函数

image-20210722231642056

使用指令: man 2 open 查看关于open的系统调用

image-20210722232237770

使用指令: man 2socket 查看关于socket的系统调用

image-20210722232851809

java -> 编译成字节码(文本文件,字节存储的序列化) -> 运行在一个用c语言写的jvm或者java进程中 -> 最终去调用内核 也就是这些系统调用

网络

IO: 可以是打开文件,也可以是socket这种网络通信
?
源不一样,产生的效果是不一样的,如果是读取文件,无非就是读取的快慢问题,如果是socket网络IO的话,会有一个读取写入的阻塞概念在里面

网络: 协议,系统调用两个层面

image-20210723200144868

TCP/IP协议其实是这4层的统称

image-20210723200401231

应用层

image-20210723201021126

使用这个和百度建立连接

8 是管理员(文件描述符) 指向一个双向得分(<>),既有输入又有输出的socket文件

image-20210723201617724

proc 目录,是内核在运行的时候,在文件系统中可以让你看到的

image-20210723213422219

echo $$  当前bash进程的pid 等同于$BASHPID
?
Bash (GNU Bourne-Again Shell) 是大多数Linux系统以及Mac OS X默认的shell,是一个为GNU计划编写的Unix shell,是一个程序,是一个gnu软件。 (外壳程序)
bash实质上是一个可执行程序,一个用户的工作环境。

image-20210723214652951

进入这个bash进程中,我们主要关注这个fd,文件描述符

image-20210723214902204

0 ? 1  2 输入输出以及报错流  用这种文件描述符表示IO
socket表示和百度的连接,这时我们建立了连接,百度就是应用层的服务器,我们这个虚拟机就相当于客户端
这时我们要给百度发送信息,但是必须遵循http协议,我们接下来测试访问百度的主页

image-20210723215620685

image-20210723223801372

echo "GET / HTTP/1.0" ? 将这个HTTP协议输出到本地 ? HTTP协议必须要请求方式(GET)  版本(1.0)
echo -e "GET / HTTP/1.0\n"  HTTP还需要有换行符 ? 用-e来处理
echo -e "GET / HTTP/1.0\n" >& 8 ? >向外输出 ? 直接使用>是输出到一个文件 >&(加数字) 才是输出到8这个文件描述符

image-20210723220335835

8具备输入输出两个方向: 常识  网络通信就是两个方向  有输入和输出
使用cat <& 8 查看输入 ?
这时我们看不到输入,因为连接超时了

image-20210723223833357

image-20210723223841815

首先: 连接和发送和接收数据是两件事
先建立连接才能发送数据,从建立连接和发送数据中间一定有时间间隔,站在百度服务器的角度,服务器准备去读取客户端传过来的信息,在这个等的过程中,不能干其他的事情,这个就叫阻塞

传输控制层

image-20210723224712760

TCP:  面向连接的可靠传输
连接三次握手: (c发送)(s发送  c接收) (c发送 s接收)确保每一方发送的都能得到回复
然后进行连接,连接是双方都为对方开辟资源!!!!  不是真的有条线连接
发送数据 当没有数据发送了开始断开连接
回收资源!!!!
四次挥手:  因为资源是对方为开辟的 如果需要断开,必须双方都发送断开的意愿并且得到对方的回复 

socket:

ip-port ip-port 四个属性确定一个连接 端口范围0-65535 所有如果连接建立长时间不发送数据就会回收socket断开连接

网络层

IP 全球唯一的

image-20210723232325453

ifconfig  查看主机的网络

当前网络配置:

networkctl status

image-20210724114010490

查看某一个网络的具体信息:

ifconfig 网卡名

image-20210724114052446

ip地址和子网掩码做与运算 : 这台计算机所在的网段 ?

image-20210724120549082

网络的通信时:

硬盘和网卡都是输入输出设备,这两个是ms毫秒级别,内存这个主存寻址时间是纳秒级别,比一切IO快了10万倍,内存可以寻址到,但是IO却不能那么快读出来,这就是瓶颈

路由表:  完成下一条
只记录当前这个主机可以访问的

image-20210724122021977

route -n ? 显示和操作路由表
Destination: 目标地址
Gateway: 网关
GenMask: 掩码
Iface: 本机地址
一个连接怎么实现:
首先我这个主机的IP是192.168.76.135,我们要访问一个IP目标地址,例如百度(61.135.169.125)
有一个判定,就是拿着我们的要访问的目标地址去和Genmask相与,得到的ip再去和Destination做比较, 默认条目
得到这个目标地址匹配后,我们要把数据发给网关,也就是路由器,路由器在发到运营商等
?
在这里先和局域网的掩码做与运算,在和其他的,因为如果是局域网和0.0.0.0与运算也能到达网关
这时出现一个问题,百度地址和网关地址不一样呀,我们通信要发送数据包,那么发送数据包应该发送谁的地址,发送网关地址,那么达到网关就结束了,网关拿到这个会认为是它的局域网,没办法继续传递,如果数据包封装百度地址,那么目标地址就不对了呀,网关就收不到了
所以IP地址 数据包只会封装百度的地址

链路层

arp协议

image-20210724133644317

数据包在IP地址上再封装arp协议,里面有下一跳网关的mac地址,路由器拿到这个数据包进行解析,根据ip判断下一跳的地址,把数据包传给下一个路由,这时ip一直是目标地址百度的,那么改变的是arp协议中的下一个网关的mac地址

下面进行抓包测试:

tcpdump -n -i ens33 arp or port 80
抓取tcp连接 通过ens33网卡的关于 arp 和80端口的数据包
arp -d 192.168.76.2 && curl www.baidu.com 80
这个指令为两条  1删除 192.168.76.2的所请求回来的mac地址 ? 2.做爬虫请求,访问主页

image-20210724135807305

image-20210724135819284

image-20210724140512646

系统调用

使用指令: man 2 socket 查看关于socket的系统调用函数

image-20210724193608482

关于socket的其他命令

image-20210724193959719

这表明socket可以是非阻塞的

image-20210724194312120

man 2 bind 执行查看系统调用关于bind的

image-20210724194953599

man 2 read  查看系统调用读取的

image-20210724195202629

这里我们看到read去读取这个文件描述符:
我们之前通过读取关于socket的系统调用可以获取到,socket是有阻塞和非阻塞的
当我们去read时,如果是阻塞的,就会一直因为socket阻塞而一直等着去读
             如果是非阻塞的,当读不到时,直接返回,什么时候心情好了再去读

BIO

image-20210724200055857

Tomcat的执行:
1.启动后,先监听Kernel内核的8080端口,假设生成一个文件描述符6
2.客户端1访问操作系统建立socket连接,并给它一个文件描述符8
3.客户端2访问操作系统建立socket连接,并给它一个文件描述符9
4.Tomcat如果想要去读取客户端的信息,就要read(8) read(9)
5.在传统的BIO中,Tomcat通过每一个连接创建一个线程进行读取,因为是阻塞的,只有这样才能保证每一个客户端读取不受阻塞影响

NIO

image-20210724203204191

Tomcat创建一个线程:
通过轮询等方式,交替访问不同的文件描述符,通过非阻塞的方式
弊端:
假设我们有1000个连接,999和是空的,那么效率是极低的,这1000次都要通过系统调用read(文教描述符),极大的消耗了内核操作cpu
一个好的程序应该是应用程序操作cpu时间多一些,系统调用操作cpu少一些

弥补NIO缺陷

内核Kernel创建一个新的系统调用,来弥补多次文件描述符的交换操作

man 2 select

image-20210724221110299

package com.bjmashibing.system.io;
?
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;
?
public class SocketNIO {
?
 ? ?//  what ? why  how
 ? ?public static void main(String[] args) throws Exception {
?
 ? ? ? ?LinkedList<SocketChannel> clients = new LinkedList<>();
?
 ? ? ? ?ServerSocketChannel ss = ServerSocketChannel.open(); ?//服务端开启监听:接受客户端
 ? ? ? ?ss.bind(new InetSocketAddress(9090));
 ? ? ? ?ss.configureBlocking(false); //重点  OS  NONBLOCKING!!!  //只让接受客户端  不阻塞
?
// ? ? ?  ss.setOption(StandardSocketOptions.TCP_NODELAY, false);
// ? ? ?  StandardSocketOptions.TCP_NODELAY
// ? ? ?  StandardSocketOptions.SO_KEEPALIVE
// ? ? ?  StandardSocketOptions.SO_LINGER
// ? ? ?  StandardSocketOptions.SO_RCVBUF
// ? ? ?  StandardSocketOptions.SO_SNDBUF
// ? ? ?  StandardSocketOptions.SO_REUSEADDR
?
?
?
?
 ? ? ? ?while (true) {
 ? ? ? ? ? ?//接受客户端的连接
 ? ? ? ? ? ?Thread.sleep(1000);
 ? ? ? ? ? ?SocketChannel client = ss.accept(); //不会阻塞?  -1 NULL
 ? ? ? ? ? ?//accept  调用内核了:1,没有客户端连接进来,返回值?在BIO 的时候一直卡着,但是在NIO ,不卡着,返回-1,NULL
 ? ? ? ? ? ?//如果来客户端的连接,accept 返回的是这个客户端的fd  5,client  object
 ? ? ? ? ? ?//NONBLOCKING 就是代码能往下走了,只不过有不同的情况
?
 ? ? ? ? ? ?if (client == null) {
 ? ? ? ? ? ? // ? System.out.println("null.....");
 ? ? ? ? ?  } else {
 ? ? ? ? ? ? ? ?client.configureBlocking(false); //重点  socket(服务端的listen socket<连接请求三次握手后,往我这里扔,我去通过accept 得到  连接的socket>,连接socket<连接后的数据读写使用的> )
 ? ? ? ? ? ? ? ?int port = client.socket().getPort();
 ? ? ? ? ? ? ? ?System.out.println("client..port: " + port);
 ? ? ? ? ? ? ? ?clients.add(client);
 ? ? ? ? ?  }
?
 ? ? ? ? ? ?ByteBuffer buffer = ByteBuffer.allocateDirect(4096); ?//可以在堆里 ? 堆外
?
 ? ? ? ? ? ?//遍历已经链接进来的客户端能不能读写数据
 ? ? ? ? ? ?for (SocketChannel c : clients) { ? //串行化!!!!  多线程!!
 ? ? ? ? ? ? ? ?int num = c.read(buffer); ?// >0  -1  0 ? //不会阻塞
 ? ? ? ? ? ? ? ?if (num > 0) {
 ? ? ? ? ? ? ? ? ? ?buffer.flip();
 ? ? ? ? ? ? ? ? ? ?byte[] aaa = new byte[buffer.limit()];
 ? ? ? ? ? ? ? ? ? ?buffer.get(aaa);
?
 ? ? ? ? ? ? ? ? ? ?String b = new String(aaa);
 ? ? ? ? ? ? ? ? ? ?System.out.println(c.socket().getPort() + " : " + b);
 ? ? ? ? ? ? ? ? ? ?buffer.clear();
 ? ? ? ? ? ? ?  }
?
?
 ? ? ? ? ?  }
 ? ? ?  }
 ?  }
?
}

image-20210724230635149

多路复用:
通过系统调用的select实现,但是这个select不是一个NIO
通过Java设置了一个过期时间,所有的步骤最终都, 落到操作系统层面,每一步都对应着系统调用
弊端:
select里面有大量文件描述符,例如1000个,每次调用select都要传递1000个文件描述符参数,会有多次拷贝的过程

epoll

使用 man epoll 学习如何使用
这里面描述了关于epoll有这样三个2类系统调用

image-20210724233202782

逐个打开

image-20210724233619438

image-20210724233913901

在这里只有一个连接创建的时候才会调用一次,换而言之,有1000次连接,只需要调用1000次epoll_ctl就行了,epoll的文件描述符,取代了之前每一个的文件描述符.

image-20210724235548348

询问服务端,我给你的epoll你现在还有没有了

image-20210724235840809

类似一个红黑树
零拷贝: sendfile(in,out) 
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-08-01 14:51:53  更:2021-08-01 14:52:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 10:57:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计