网络流的结尾(end of stream)是什么?
在java.io
包中大多数read
方法的 javadoc 中,可以读到
the total number of bytes read into the buffer,
or -1 if there is no more data because the end of the stream has been reached
大致意思是:读取到缓冲区的字节总数,或 -1,如果没有更多的数据,因为已经达到流的结尾
我们都知道 读取文件时,只要读取到 文件的 EOF 标志位,就代表文件读取完成了,inputStream 就会返回 -1,代表可以结束读取了,因此,这 个 EOF 不需要我们主动去判断。
但是,我从未真正获得 -1,因为大多数流(在网络的情况下) 流(我最常使用的流)只是阻塞程序执行,直到在远程端将某些内容写入流中,才会继续执行。
因为 socket 是基于 TCP/IP 规则,编写的程序,那么,就涉及到 TCP/IP 数据包的结构了,所以,我想,socket之间也是通过 改变数据包中某个标志位通知对方的,让对方改变 socket中的 shutOut=true
。
public
class Socket implements java.io.Closeable {
/**
* Various states of this socket.
*/
private boolean created = false;
private boolean bound = false;
private boolean connected = false;
private boolean closed = false;
private Object closeLock = new Object();
// shutDownInputStream
private boolean shutIn = false;
// shutDownOutputStream
private boolean shutOut = false;
}
经过代码调试,我发现 read
是一个阻塞函数,如果A端没有主动断开OutputStream
(输出流),那么,B端就会认为A端仍旧可能发送数据。
像 read这种阻塞读取函数还有:
BufferedReader#readLine
、DataInputStream#readUTF
等。
代码测试
客户端
public class SocketClient {
public static void main(String[] args) throws IOException {
Socket client;
OutputStream out = null;
InputStream input = null;
try {
client = new Socket("127.0.0.1",8888);
out = client.getOutputStream();
input = client.getInputStream();
// 测试1:主动 end of stream
// client.shutdownInput();
// 发送
out.write("0".getBytes());
out.flush();
// 注意:缓冲区满了,不是end of stream
byte[] buf = new byte[5];
int size;
// 读取
while ((size = input.read(buf,0,buf.length)) != -1) {
System.out.println("[" + size + "] byte: " + new String(buf));
// 相当于 自己强制 end if stream,自己的 read 方法会返回 -1
// 相当于,我不想在读了,返回 -1 自我结束
// 对 服务端 没有任何影响
// client.shutdownInput();
}
System.out.println(size);
} catch (IOException e) {
e.printStackTrace();
} finally {
assert out != null;
out.close();
assert input != null;
input.close();
}
}
}
服务端
public class SocketServer {
public static void main(String[] args) {
SocketServer ss = new SocketServer();
int port = 8888;
try {
ss.startServer(port);
} catch (Exception e) {
e.printStackTrace();
}
}
public void startServer(int port) {
try (ServerSocket serverSocket = new ServerSocket(port)) {
Socket server;
System.out.println("server socket is start……");
while (true) {
server = serverSocket.accept();
try {
InputStream in = server.getInputStream();
OutputStream out = server.getOutputStream();
byte[] buf = new byte[5];
int size;
while ((size = in.read(buf,0,buf.length)) != -1) {
System.out.println("[" + size + "] byte: " + new String(buf));
// 测试 1:写回 3 个字节
out.write("111".getBytes());
// 测试二:每 1 秒,写回 一个 1
// for (int i = 0;i < 10;i++){
// out.write("1".getBytes());
// // 休眠 1 秒
// // TimeUnit.SECONDS.sleep(1);
// }
// 测试3:关闭输出流,告诉 客户端的 read 方法,end of tream
// 因此,客户端的 read 方法 会 返回 -1
// server.shutdownOutput();
}
System.out.println(size);
out.flush();
} catch (Exception e) {
e.printStackTrace();
break;
} finally {
System.out.println("close client socket");
server.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
如何触发 end of stream ?
- Socket任意一端在调用
Socket#shutdownOutput
方法, 关闭outPutStream
(输出流),这样对应的另一端的Socket#inputStream
上的read
方法就会返回 -1,
注意: 不能调用
Socket#getInputStream().close()
。因为它会导致socket直接被关闭。 当然,如果不需要继续在socket上进行读操作,也可以直接关闭socket。但是这个方法不能用于通信双方需要多次交互的情况。
// 调用shutdownOutput 通知对端的 read 方法返回 -1
socket.shutdownOutput();
- Socket任意一端在调用
Socket#shutdownInput
方法, 那么,调用这个方法的一端的inputStream
,相当于end of stream
了,以后就没办法再读取数据了。但是,这个方法对另一端没有任何影响。
大白话就是:我不想再读了,自我了结,强制让 read方法返回 -1。
socket.shutdownInput();
- 如果任意一端强制掉线(就是程序被强制停止了)或者主动调用
socket#close
方法,那么,另一端的read
方法就会抛出异常。
java.net.SocketException: Software caused connection abort: recv failed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at test.socket.SocketServer.startServer(SocketServer.java:41)
at test.socket.SocketServer.main(SocketServer.java:24)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/69730.html