toppic
当前位置: 首页> 穿越小说> IO流中「线程」模型总结

IO流中「线程」模型总结

2023-07-18 06:39:27
50G POL

客户端与服务端进行通信「交互」,可能是同步或者异步,服务端进行「流」处理时,可能是阻塞或者非阻塞模式,当然也有自定义的业务流程需要执行,从处理逻辑看就是「读取数据-业务执行-应答写数据」的形式。

一、基础简介

在io流的网络模型中,以常见的「客户端-服务端」交互场景为例;

客户端与服务端进行通信「交互」,可能是同步或者异步,服务端进行「流」处理时,可能是阻塞或者非阻塞模式,当然也有自定义的业务流程需要执行,从处理逻辑看就是「读取数据-业务执行-应答写数据」的形式;

java提供「三种」io网络编程模型,即:「bio同步阻塞」、「nio同步非阻塞」、「aio异步非阻塞」;

二、同步阻塞

1、模型图解

bio即同步阻塞,服务端收到客户端的请求时,会启动一个线程处理,「交互」会阻塞直到整个流程结束;

这种模式如果在高并发且流程复杂耗时的场景下,客户端的请求响应会存在严重的性能问题,并且占用过多资源;

2、参考案例

【服务端】启动serversocket接收客户端的请求,经过一系列逻辑之后,向客户端发送消息,注意这里线程的10秒休眠;

public class socketserver01 {(string[] args) throws exception {// 1、创建socket服务端= new serversocket(8080);// 2、方法阻塞等待,直到有客户端连接= serversocket.accept();// 3、输入流,输出流= socket.getinputstream();= socket.getoutputstream();// 4、数据接收和响应int readlen = 0;[] buf = new byte[1024];((readlen=instream.read(buf)) != -1){// 接收数据= new string(buf, 0, readlen) ;.out.println("readvar======="+readvar);}// 响应数据.sleep(10000);.write("sever-8080-write;".getbytes());// 5、资源关闭.ioclose(outstream,instream,socket,serversocket);}}

【客户端】socket连接,先向serversocket发送请求,再接收其响应,由于server端模拟耗时,client处于长时间阻塞状态;

public class socketclient01 {(string[] args) throws exception {// 1、创建socket客户端= new socket(inetaddress.getlocalhost(), 8080);// 2、输入流,输出流= socket.getoutputstream();= socket.getinputstream();// 3、数据发送和响应接收// 发送数据.write("client-hello".getbytes());// 接收数据int readlen = 0;[] buf = new byte[1024];((readlen=instream.read(buf)) != -1){= new string(buf, 0, readlen) ;.out.println("readvar======="+readvar);}// 4、资源关闭.ioclose(instream,outstream,socket);}}

三、同步非阻塞

1、模型图解

nio即同步非阻塞,服务端可以实现一个线程,处理多个客户端请求连接,服务端的并发能力得到极大的提升;

这种模式下客户端的请求连接都会注册到selector多路复用器上,多路复用器会进行轮询,对请求连接的io流进行处理;

2、参考案例

【服务端】单线程可以处理多个客户端请求,通过轮询多路复用器查看是否有io请求;

public class socketserver01 {(string[] args) throws exception {{//启动服务开启监听= serversocketchannel.open();.socket().bind(new inetsocketaddress("127.0.0.1", 8989));// 设置非阻塞,接受客户端.configureblocking(false);// 打开多路复用器= selector.open();// 服务端socket注册到多路复用器,指定兴趣事件.register(selector, selectionkey.op_accept);// 多路复用器轮询= bytebuffer.allocatedirect(1024);(selector.select() > 0){set<selectionkey> selectionkeys = selector.selectedkeys();<selectionkey> selectionkeyiter = selectionkeys.iterator();(selectionkeyiter.hasnext()){= selectionkeyiter.next() ;.remove();(selectionkey.isacceptable()) {// 接受新的连接= socketchannel.accept();// 设置读非阻塞.configureblocking(false);// 注册到多路复用器.register(selector, selectionkey.op_read);} else if (selectionkey.isreadable()) {// 通道可读= (socketchannel) selectionkey.channel();int len = client.read(buffer);(len > 0){.flip();[] readarr = new byte[buffer.limit()];.get(readarr);.out.println(client.socket().getport() + "端口数据:" + new string(readarr));.clear();}}}}} catch (exception e) {.printstacktrace();}}}

【客户端】每隔3秒持续的向通道内写数据,服务端通过轮询多路复用器,持续的读取数据;

public class socketclient01 {(string[] args) throws exception {{// 连接服务端= socketchannel.open();.connect(new inetsocketaddress("127.0.0.1", 8989));= bytebuffer.allocate(1024);= "client-hello";.put(convar.getbytes());.flip();// 每隔3s发送一次数据(true) {.sleep(3000);.rewind();.write(writebuffer);.clear();}} catch (exception e) {.printstacktrace();}}}

四、异步非阻塞

1、模型图解

aio即异步非阻塞,对于通道内数据的「读」和「写」动作,都是采用异步的模式,对于性能的提升是巨大的;

这与常规的第三方对接模式很相似,本地服务在请求第三方服务时,请求过程耗时很大,会异步执行,第三方第一次回调,确认请求可以被执行;第二次回调则是推送处理结果,这种思想在处理复杂问题时,可以很大程度的提高性能,节省资源:

2、参考案例

【服务端】各种「accept」、「read」、「write」动作是异步,通过future来获取计算的结果;

public class socketserver01 {(string[] args) throws exception {// 启动服务开启监听= asynchronousserversocketchannel.open() ;.bind(new inetsocketaddress("127.0.0.1", 8989));// 指定30秒内获取客户端连接,否则超时<asynchronoussocketchannel> acceptfuture = socketchannel.accept();= acceptfuture.get(30, timeunit.seconds);(asychannel != null && asychannel.isopen()){// 读数据= bytebuffer.allocate(1024);<integer> readresult = asychannel.read(inbuffer);.get();.out.println("read:"+new string(inbuffer.array()));// 写数据.flip();<integer> writeresult = asychannel.write(bytebuffer.wrap("server-hello".getbytes()));.get();}// 关闭资源.close();}}

【客户端】相关「connect」、「read」、「write」方法调用是异步的,通过future来获取计算的结果;

public class socketclient01 {(string[] args) throws exception {// 连接服务端= asynchronoussocketchannel.open();<void> result = socketchannel.connect(new inetsocketaddress("127.0.0.1", 8989));.get();// 写数据= "client-hello";= bytebuffer.wrap(convar.getbytes());<integer> writefuture = socketchannel.write(reqbuffer);.get();// 读数据= bytebuffer.allocate(1024);<integer> readfuture = socketchannel.read(inbuffer);.get();.out.println("read:"

友情链接