【问题标题】:JAVA : BufferdInputStream and BufferedOutputStreamJAVA:BufferdInputStream 和 BufferedOutputStream
【发布时间】:2012-09-02 18:00:49
【问题描述】:

我有几个问题-

1. 我有两台计算机通过套接字连接。程序执行时

outputStream.writeInt(value);
outputStream.flush();

实际发生了什么?程序是否等到另一台计算机读取整数值?

2. 如何清空outputStreaminputStream?意思是,当清空时 outputStreaminputStream,写入该流的任何内容都会被删除。 (请不要建议通过关闭连接来做到这一点!) 我试着用这种方式清空inputStream-

byte[] eatup=new byte[20*1024];
int available=0;
while(true)
{
    available=serverInputStream.available();
    if(available==0)
       break;
    serverInputStream.read(eatup,0,available);
}
eatup=null;

String fileName=(String)serverInputStream.readObject();

程序不应处理该行,因为 outputStream 上没有写入任何其他内容。 但是我的程序无论如何都会执行它并抛出一个java.io.OptionalDataException 错误。

注意:我正在做一个客户端-服务器文件传输项目。客户端发送文件到 服务器。第二个代码用于服务器终端。如果在服务器上按下“取消按钮” 然后它停止从serverInputStream 读取字节并发送一个信号(我使用int -1) 给客户。当客户端收到此信号时,它会停止向服务器发送数据,但我已经 注意到serverInputStream 不是空的。所以我需要清空这个serverInputStream,这样 客户端计算机能够再次发送服务器计算机文件(这就是我无法管理锁的原因 来自read方法)

【问题讨论】:

  • 您真的不应该使用available 来确定要读取多少bytes。 available 的某些实现将始终返回0,然后您的代码将无法工作。只需尝试完全填满缓冲区并检查 read 的返回值,看看实际读取了多少 bytes。
  • while(serverInputStream.read(eatup,0,available)!=-1);
  • @Jeffrey 但是如果我为此目的使用read 方法,当没有字节可读取时,程序将阻塞(文档是这样说的),这是我不想要的。
  • @Jisean - 如果您需要在接收端检测“消息结束”而不关闭连接,那么您需要构建一个基本的消息协议。请参阅我的答案以获取示例(大小前缀)
  • @JisanMahmud 你为什么要丢弃InputStream 上的已有数据?

标签: java stream inputstream outputstream


【解决方案1】:

1 - 否。在 flush() 上,数据将被写入操作系统内核,操作系统内核可能会立即将其交给网卡驱动程序,然后由网卡驱动程序将其发送到接收端。简而言之,发送就是一劳永逸。

2 - 正如 Jeffrey 评论的那样,available() 对于这种操作是不可靠的。如果做阻塞 IO,那么正如他建议的那样,你应该只是投机地使用 read() 。但是应该说,您确实需要在原始流之上定义一个协议,即使它只是使用 DataInput/DataOutputStream。使用原始写入/读取时,黄金法则是一次写入!= 一次读取。例如,如果您要在一侧写入 10 个字节,而在另一侧有一个读取循环,则无法保证一次读取将读取所有 10 个字节。它可以作为块的任何组合被“读取”。类似地,两次 10 字节的写入可能会在接收端显示为一次 20 字节的读取。换句话说,除非您在原始字节之上创建更高级别的协议来执行数据包,否则没有“数据包”的概念。例如,每次发送都以字节长度为前缀,因此接收方知道当前数据包中预期有多少数据。

如果您确实需要做比基本应用程序更复杂的事情,我强烈建议您研究一些已经解决了网络 IO 的许多棘手问题的更高级别的库。我会推荐 Netty 用于生产应用程序。然而,从简单的 IO 流到 Netty 的更多基于事件的系统的理解是一个很大的飞跃。中间的某个地方可能还有其他库。

【讨论】:

  • '定义一个协议'对我来说有点高级,这只是我在'客户端-服务器文件共享'上的大学 JAVA 项目。不过感谢您的信息,解决了一些困惑!
  • 不客气。如果您只想要一些基本的东西,请使用 DataInputStream 和 DataOutputStream 并将读取与写入匹配。这将支持您需要的大部分内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-11
  • 1970-01-01
  • 2020-07-15
  • 2013-07-05
相关资源
最近更新 更多