阅读目录
上面虽然实现了客户端与Server端的通信,但是缺点也很明显。
- 在使用IO和Socket构造网络服务时 接收连接:accept(),接收请求数据,发送响应数据都可能引起阻塞的操作。、
- 线程从Socket输入流读数据时,如果没有足够的数据就会进入阻塞状态,直到读够了足够的数据,或者达到输入流的末尾,或者出现了异常,才能从输入流的read()方法返回或异常中断。
输入流中有多少数据才算足够呢?这要看执行read()方法的类型。
int read()只要输入流中有一个字节就算足够。
int read(byte[] buff) 只要输入流中的字节数目与参数buff数组的长度相同,就算足够。(这个方法的好处 可以看看适配器设计模式中的知识点)
String readLine() 只要输入流中有一行字符串就算足够(BufferReader类中才有此方法)。
Socket网络通信改进
以上两个阻塞式的方法住我们的当前线程。服务器可以使用多线程来处理阻塞I/O,尽管能满足同时响应多个客户请求的需求,但是增加了java虚拟机调度线程的负担。
在阻塞模式下,
- read()方法会争取读到n个字节,如果输入流中不足n个字节,就进入阻塞状态,直到读取了n个字节,或者读到了输入流末尾,或者出现了I/O异常。
- socket.accept()方法如果没有接收到连接,也会一直等待
在非阻塞模式下
- read()方法奉行能读到多少数据就读到多少数据的原则。read()方法读取当前通道中的可读数据,有可能不足n个字节,或者为0个字节,read()方法总会立刻返回。而不会等到读取了n个字节才返回,read()方法返回实际上读入的字节数。SocketChannel extends AbstractSelectableChannel 类的中 int read(ByteBuffer dst)方法是非阻塞式的。
- ServerSocketChannel或SockeChannel通过register()方法向Selector注册事件时,register()方法会创建一个SelectionKey对象,这个SelectionKey对象是跟踪注册事件的句柄。在SelectionKey对象有效期,Selector会一直监控与SelectorKey对象相关的事件,如果事件发生,就会把SelectionKey对象加入到Selector-keys集合中。https://www.cnblogs.com/ssskkk/p/9557667.html
