【问题标题】:Reading from an InputStream of a Socket从 Socket 的 InputStream 中读取
【发布时间】:2017-07-15 02:16:29
【问题描述】:

我有一个到 W&T 的 COM-Server ++ 的 Socket 连接,它连接到 Internet,还通过 Serial-to-USB 连接到我的 PC。

用于 TCP 出站通信的 COM-Server 的设置是:

激活。数据包选项:禁用
不活动。超时:00030
连接。超时:00300
断开连接字符:000
客户端: "C"+Addr : 禁用
响应模式 : 禁用

在我的应用程序中,我像这样读取此服务器的传入数据:

    boolean running = true;
log.info( "{0}: Starting to listen for input data", name );
while ( running )
{
  try
  {
    int charsRead = inputStream.read( buffer );

    if ( charsRead < 0 )
    {
      running = false;
    }
    else
    {
      byte[] received = Arrays.copyOf( buffer, charsRead );
      /** TODO: Call interface of protocol here */
      log.info( "{0}: data received: {1}", connection.getName(), new String( received ) );
    }
  }
  catch ( IOException ie )
  {
    setStatus( ConnectionStatus.FAILURE );
    close();
    /** TODO: Exception handling */
    running = false;
  }
}

如果我从设备发送:test&lt;CR&gt;&lt;LF&gt;,我得到的日志输出是:

(terminal1) terminal1: data received: t
(terminal1) terminal1: data received: e
(terminal1) terminal1: data received: st
(terminal1) terminal1: data received: 
(terminal1) terminal1: data received: 

然而,所需的输出是:

(terminal1) terminal1: data received: test  

我的错误在哪里,或者我假设 InputStream 的读取方法的工作流程是错误的?

【问题讨论】:

  • DOC public abstract int read() throws IOException 从输入流中读取数据的下一个字节 public int read(byte[] b) throws IOException 从输入流中读取一些字节输入流
  • 哦,好吧,所以他没有读到最后。从技术上讲,等待一段时间完成然后注销缓冲区将完全返回所需的结果,对吗?
  • 只需将读取的内容附加到数组中,直到结束,仅此而已
  • 简单回答:流仅提供字节传输。除此之外的任何事情,例如将 messages 映射到字节和从字节映射,都需要在此之上实现。这就像确保每个“消息”都以换行符结尾(当“消息”是单行文本时)一样简单。

标签: java sockets serial-port


【解决方案1】:

我并不完全了解这个库。但是一个流返回它得到的东西,没有人确保它实际上是它的全部...... 这可能会解决您的问题:How to read all of Inputstream in Server Socket JAVA

编辑:您还可以尝试使用 ObjectInputStream(如果可能)将字符串作为对象。

【讨论】:

  • 我只是在使用java.net.Socket,这个套接字有一个你得到的InputStream,类是java.io.InputStream,所以它基本上是vanilla Java。我只是想为可能知道当时可能存在的更具体问题的人提供 COM-Server 信息。我将看看提到的方法
  • 我刚刚检查过,readFully() 函数对我不可用。我只有 read(),read(byte[]),skip,reset,close 和 read(byte[],int,int)...Eclipse 和文档告诉我它是 java.io.InputStream 然而..
  • @kleopi:评论前请检查Answer from @Lolo
  • 好吧,对不起,我可能搞砸了。为了进一步参考,我发现了这个:stackoverflow.com/questions/19839172/…
  • ObjectInputStream 是不可能的,因为我有一个普通的 tcp 通信,它将在上面的一层中处理以使用不同的协议。此流添加了一个不利于以后使用的标头。仍然感谢您的想法
【解决方案2】:

一个简单的解决方案如下所示:

StringBuilder sb = new StringBuilder();

int c;

while ( (( c = inputStream.read() ) >= 0) && (c != 0x0a /* <LF> */) ) {
  if ( c != 0x0d /* <CR> */ ) {
    sb.append( (char)c );
  } else {
    // Ignore <CR>.
  }
}

return sb.toString();

此代码一直读取字节,直到找到行尾(或流的结尾),由 &lt;LF&gt; 发出信号。

我们期望&lt;CR&gt;&lt;LF&gt; 其中&lt;CR&gt; 是行分隔符的一部分,因此我们在收集所有其他字节时忽略任何&lt;CR&gt;

【讨论】:

  • 这可以满足我的需要:) 谢谢你,使用 inputStream 本身进行循环的想法非常好。想知道为什么我没有想到这一点
  • 快速提问。我再次对此进行了测试,发现流在大约 30 秒后关闭。我在它周围附加了另一个while循环以在套接字仍连接到远程设备时继续循环。在我看来,这是一个肮脏的黑客行为。那么有没有更好的方法来保持流始终打开?
  • "Inactiv. Timeout : 00030" - 您可能需要在这 30 秒用完之前发送一些东西,让设备知道您仍然在那里。否则,设备可能会认为连接处于“非活动状态”并关闭它。
  • 哦,我现在觉得自己很愚蠢……今天绝对不是我最开心的一天。自从我设置了keepAlive选项以来,我一直在想。谢谢你:)
猜你喜欢
  • 2015-05-23
  • 1970-01-01
  • 2015-07-11
  • 2021-09-30
  • 2012-03-03
  • 2014-09-15
  • 2011-08-07
  • 2018-06-26
相关资源
最近更新 更多