BIONIO编程与直接内存零拷贝深入辨析
Socket
Socket是处于应用层和传输层中间的软件,是一个接口,我们应用层可以直接调用接口来实现网络连接,Socket帮我们实现了传输层和网络层复杂逻辑。每创建个连接就会创建一个Socket。
image20230215220048528BIO
BIo即BlockingIO,阻塞IO。
在Socket中存在两种阻塞,一个accept,另外一个是SocketIO的读,
accept是阻塞在应用层的,当有连接进来的时候,服务器接受信息(连接信息),并且发送中断信号唤醒accept线程。它不会影响传输层TCP的连接。
SocketIO每创建socket时候都会创建两个socket缓存区。分别是读写,每当有数据过来时候会写入到Socket读取缓冲区内。发送中断信号唤醒客户端线程进行读取。
BIO相比较传输效率更快,但是服务器必须为每个客户端单开一个线程,客户端连接成本大,不能只能大量的连接。
服务器publicclassServer{privatestaticExecutorServiceexecutorServiceExecutors。newFixedThreadPool(Runtime。getRuntime()。availableProcessors());publicstaticvoidmain(String〔〕args)throwsIOException{服务端启动必备ServerSocketserverSocketnewServerSocket();表示服务端在哪个端口上监听serverSocket。bind(newInetSocketAddress(6666));System。out。println(服务端开启。。。。。。);try{while(true){阻塞,等待有新的连接过来如果TCP,传输层有新的连接,才会进入到这里,这里阻塞是应用层的阻塞,不影响TCP连接SocketacceptserverSocket。accept();executorService。execute(newThread(newServerTask(accept)));}}finally{serverSocket。close();}}每有客户端建立连接,都会有对应的Task来处理privatestaticclassServerTaskimplementsRunnable{privateSocketsocketnull;publicServerTask(Socketsocket){this。socketsocket;}Overridepublicvoidrun(){try(实例化与客户端通信的输入输出流ObjectInputStreaminputStreamnewObjectInputStream(socket。getInputStream());ObjectOutputStreamoutputStreamnewObjectOutputStream(socket。getOutputStream())){如果webSocket输入流中没有数据,阻塞StringtextinputStream。readUTF();System。out。println(服务器收到的消息:text);outputStream。writeUTF(服务器返回的消息:text);outputStream。flush();}catch(Exceptione){e。printStackTrace();}finally{try{socket。close();}catch(IOExceptione){e。printStackTrace();}}}}}
客户端publicclassClient{publicstaticvoidmain(String〔〕args)throwsIOException{客户端启动必备Socketsocketnull;实例化与服务端通信的输入输出流ObjectOutputStreamoutputnull;ObjectInputStreaminputnull;服务器的通信地址InetSocketAddressaddrnewInetSocketAddress(127。0。0。1,6666);try{socketnewSocket();socket。connect(addr);outputnewObjectOutputStream(socket。getOutputStream());inputnewObjectInputStream(socket。getInputStream());向服务器输出请求output。writeUTF(你好服务器。。。。。。);output。flush();这里读取是阻塞的。System。out。println(input。readUTF());}finally{if(socket!null)socket。close();if(output!null)output。close();if(input!null)input。close();}}}阻塞IO和非阻塞IO
阻塞IO,指的是需要等待内核IO准备好后,才返回到用户空间执行用户的操作。阻塞是指用户空间的执行状态。
非阻塞IO,指的是用户空间的程序不需要等待内核IO操作彻底完成,可以立即返回用户空间执行用户操作,即处于非阻塞IO状态,内核空间会立即返回给用户一个状态值。调用线程拿到内核返回的状态值后,IO操作能干就干,不能就干别的事情。
JAVAIO的各种流是阻塞的,意味着read()或write()时,线程阻塞,直到一些数据被读取,或者数据完全写入。再此期间线程不能干任何事情。
JAVANIO的非阻塞模式,线程从通道读取数据,仅能得到可用的数据,如果没有数据,什么都不会获取,线程不会阻塞。
针对网络IO的操作,可以分成两个阶段,准备阶段和操作阶段。
1,准备阶段是判断是否能够操作(即等待数据是否可用),在内核进程完成的;
2,操作阶段则执行实际的IO调用,数据从内核缓冲区拷贝到用户进程缓冲区。
一个read()操作发生时,它会经历下面两个阶段:
A,等待数据准备,数据是否拷贝到内核缓冲区;
B,将数据从内核拷贝到用户进程空间
那么在Socket。read()阻塞在当前操作系统的准备阶段,我还没准备好,稍等会。
Buffer如果里边有数据就返回,没有数据就不返回,不需要等待它有没有准备好。Reactor模式
Reactor翻译过来是反应堆模式,大致是将要关注的事件扔到反应堆里边,当有关注的事件发生时候,反应堆就会告诉我们。
在内核中新开启个线程Selector,这个线程是阻塞状态,把socket放入到这个Selector线程里边,当有socket发生事件就会给Selector线程发送中断信号来唤醒select。
Reactor模式,是一种高效的异步IO模式特征是回调。
与观察者模式区别是,观察者模式是对单个事件感兴趣,Reactor是对多个事件感兴趣。
单线程Reactor模式
Reactor放入一个关注连接的事件,当有客户端发生连接时候,Reactor就会关注到,并且唤醒accept接受连接,产生一个Socket,这个socket关注读并放入到Reactor中,当我们socket读取的时候会阻塞主线程,当有新的客户端连接过来的时候,由于主线程阻塞在read那里,导致服务器没有办法响应新客户端的连接,但是这个时候TCP其实已经连接上,客户端也收到连接成功。
image20230216123720734
多线程Reactor模式
多线程Reactor相比较于单线程,它会为每一个新连接的客户端Socket分配一个线程,这样socket读取不会影响主线程。如果客户连接相对较多就会分配更多的线程。
image20230216124456447
主从Reactor模式
在相比较多线程模式下,当有大量的连接过来,那么在反应堆中就会存在大量的Socket线程关注着读写,然而关注连接的相比较会太少,所以将关注连接的和关注读写的反应堆分开
image20230216124923655NIO三大核心组件
Selector:选择器,Channel:管道,buffer:缓冲区
Selector:也被叫做事件订阅器,NIO可以通过Selector来管理多个channel
channel:是程序和系统交换数据的渠道。
buffer:面向缓冲的,非阻塞。用于与channel交换数据。
image20230216163501615
其中7,8是应用程序主动调用的。只有Socket创建的两个缓冲区是操作系统主动调用。
NIO代码
需要注意的是:
1:客户端再connect后需要判断是否连接上,因为connect是异步操作,可能没连接上需要注册连接事件
2:for循环keys去除key应该先从Iterator中删除,因为他不会自己删除,下次再来的话还会再此处理它。
keys是保存在sun。nio。ch。SelectorImplpublicSelectedKeys,SetpublicSelectedKeys;如果不手动剔除的话,不会自动剔除。SelectKeyServerSocketChannelssc(ServerSocketChannel)selectionKey。channel();socketChannel。register(selector,SelectionKey。OPCONNECT);
SelectKey表示channel和selector建立了关系,并维护了channel事件。
selectKey事件有四种:读,写,连接,就绪
OPREAD:读,当socket的读缓冲区有数据时候触发。
OPWRITE:写,当socket的写缓冲区空闲时候触发,没必要注册该事件,啥时候写自己知道,不用操作系统通知。
OPCONNECT:就绪,当请求连接成功后触发。该操作只给客户端使用。
OPACCEPT:当接受到一个客户端连接请求时触发,只给操作系统用。直接内存
image20230216170228528channel。write(writeBuffer);
当writeBuffer大于Data(Socket缓冲区的时候)write将不会返回(如果是同步的,将阻塞,直到所有数据发送到缓冲区)。write返回数据,仅仅表示buffer写入缓冲区成功,仅仅表示可以重新使用原来的缓冲区,TCP对端不一定收到消息。
IO读写基本要求,一个地址通过JNI传递给C库的时候,这个地址不能失效。所以在JDK在写的时候必须先创建一个堆外内存DirectBuffer,并且把数据复制到堆外内存,一个GC管不了的地方。因为JDK堆内存有GC地址会变化。DirectBuffer只有当执行老年代FullGC的时候才会顺便回收直接内存。
image20230216172743640
堆外内存的优缺点
优点:
1:避免重复复制。节省一次复制,节省一次用户态转内核态。
2:减少了垃圾回收的工作。
缺点:
1:内存泄漏,不好排查。
2:不适合存储复杂对象。
3:堆外内存创建比堆内内存创建复杂。零拷贝
零拷贝是指CPU不需要将数据从某处复制到另一处。
减少不必要的中间拷贝,不是说的不拷贝,只是说减少冗余的拷贝。例如:Netty,kafka,Rocketmq
我cpu一秒钟几亿上下,你却让我陪你吃杂碎面
DMA(DirectMemoryAccess,直接内存存取)是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依于CPU的大量中断负载。否则,CPU需要从来源把每一片段的资料复制到暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU对于其他的工作来说就无法使用。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与IO设备开辟一条直接传送数据的通路,能使CPU的效率大为提高。DMA内核中的操作。
程序IO读取数据:
1:DMA将数据准备好,从磁盘(硬件层)读取到内核空间。
2:用户程序,从内核拷贝到用户空间。byfferfile。read();Socket。send(buffer);
image20230216203531487
传统发送文件需要四次上下文切换,五次拷贝。MMAP内存映射
将应用程序上的数据和应用缓冲区进行映射。建立一一对应关系。减少一次DMA拷贝。
image20230218180656458sendfile
DMA将磁盘数据复制到内核中的kernelbuffer,然后将内核中的kernelbuffer拷贝到socketbuffer,将kernelbuffer直接拷贝到Socketbuffer中,并不是真正的拷贝,只是将内存地址和长度拷贝到缓冲区。DMA将数据直接从内核传递给协议引擎。需要硬件支持。
NIO利用的是sendfile()。NIO提供FileChannel拥有transferTo和transferFrom两个方法。可以直接把FileChannel中的数据直接拷贝到另外一个Channel。或者Channel拷贝到FileChannel。
image20230216203737075splice
不需要硬件支持,从linux2。6。17开始。数据从磁盘读取到内核OS,在内核直接可以与Socketbuffer建立pipe管道。
image20230216204121953
桦树茸的功效及副作用桦树茸的好处和坏处桦树茸很多人都只是有所耳闻,不是很了解,下面5号网的小编为你们介绍桦树茸的功效及副作用,桦树茸的好处和坏处。桦树茸的功效及副作用降血糖防并发:桦茸精粉最有效成分是多糖,水……
swisse番茄红素怎么样?swisse番茄红素功效swisse家的保健品一直都是深受大家欢迎的,swisse番茄红素这款保健品大家可能还不是太了解,下面5号网的小编为你们介绍swisse番茄红素怎么样?swisse番茄红素功效……
豪门悲喜夜!拜仁破纪录晋级,利物浦大屠杀,国米送巴萨奔向欧联本周欧冠第四轮的小组赛全面开打,用一个词来形容第一个比赛日的赛况,那就是冷门不断,尤文惨遭海法马卡比羞辱,客场2球完败,曼城、皇马和大巴黎三大冠军热门球队则全部被非五大联赛球队……
易瑞沙价格易瑞沙多少钱?易瑞沙是一款治疗癌症的药品,据说价格是很高的,那么这个药价格到底是多少钱呢,下面5号网的小编为你们介绍易瑞沙价格易瑞沙多少钱?易瑞沙价格易瑞沙的主要成份为吉非替尼,临床上……
2亿欧元打水漂!巴萨出局创耻辱纪录,高层后悔,承认哈维被高估足球助力团欧冠小组赛33战平国米,巴萨几乎出线希望渺茫,哈维的信誉和信任也遇到严重的质疑。对哈维来说,下场国家德比或许是他的最后一颗救命稻草!据《每日体育报》消息,……
漂亮能为人生加成多少这几天看到的娱乐圈新闻,比较有意思的是吉赛尔邦辰和她那位橄榄球传奇老公汤姆布雷迪离婚,而离婚的原因是汤姆原本承诺吉娘娘今年退役,回归家庭,和吉娘娘一起照顾孩子。结果退役不过40……
台湾地区9月出口年减5。3中止连26红中国台湾网10月8日讯据香港中评社报道,全球经贸吹冷风,台当局财务主管部门昨天公布9月出口金额375。3亿美元、年减5。3,低于预期,连续26个月正成长纪录划下句点。台财……
叶酸会导致胎停育吗?叶酸过量也不好有的人说叶酸搞不好会导致胎停育,这种说法还是蛮吓人的,下面5号网的小编为你们介绍叶酸会导致胎停育吗?叶酸过量也不好。叶酸会导致胎停育吗从医学的角度来看,吃叶酸跟停胎之间没……
风湿会引起发烧吗?风湿会引起胎停吗?风湿有时候会有一些并发症,很多人不知道风湿会引起哪些症状,下面5号网的小编为你们介绍风湿会引起发烧吗?风湿会引起胎停吗?风湿会引起发烧吗风湿是会引起发烧的。发热是风……
生死狙击2银币皮肤获得方法介绍《生死狙击2》银币皮肤是游戏中的一种比较难获取的皮肤,对于一些玩家来说这些皮肤可能是他们比较喜欢的类型,可能有玩家还不知道银币皮肤要怎么才能够获得,下面小编就给大家整理了具体的……
睡觉突然抖一下惊醒怎么办是这些因素睡觉时我们每天都会做的事情,睡觉的时候很多人都遇到过睡着了突然抖一下惊醒的状况,在生活中很常见,相信很多人都有过,如果比较的频繁就需要注意,那么睡觉突然抖一下惊醒怎么办?是这些……
脖子后面有痣代表什么?10大身体缺陷是好事痣是我们每个人或多或少都会长的,很多人觉得身上长痣不太美观,就会去把痣去掉,我们都知道每个身体部位长的痣都是有不同意义的,很多人脖子后面都会长痣,那么脖子后面有痣代表什么?10……