3

我试图想出一个好的标题,但似乎失败了。这是我的问题:

我正在从套接字读取数据。缓冲区中包含的数据是一个序列化的对象。一旦数据被完全读取,我就可以创建一个 ObjectInputStream 并使用 readObject 来读取数据。

我的问题是,因为我的套接字类正在读取字节......我怎么知道我什么时候收到了完整的对象?对象指示器似乎没有结束,我尝试寻找序列化字节码的突破以查看是否可以找到长度字段,但序列化字节码在谷歌可以找到的任何地方都没有得到很好的解释。

我收到的对象是哈希映射(java.util.Map),如果这有区别的话。

这是我正在使用的部分代码:

long start = System.currentTimeMillis();
long end = start + (getTimeout() * 1000);   
m_Ipports.send(dataToSend);       
m_Waiting = true;        
while (m_Waiting) {
  // Data is read in a separate thread, and stored into the byte buffer m_DataIn
  if (System.currentTimeMillis() > end) {
    //throw new Exception("Timeout waiting for response.");             
    m_Waiting = false;  // hack to get it to work. Times out every time.
  }
  m_Ipports.doEvents();
}
ByteArrayInputStream bis = new ByteArrayInputStream(m_DataIn.toByteArray()); 
ObjectInputStream ois = new ObjectInputStream(bis);        
Object o = ois.readObject();             
Map m = (Map)o;

所以,我的问题是,当我阅读 m_DataIn 时,我如何确定我已经到达对象的末尾?

注意:我不能以任何方式修改我从中接收这些对象的服务器。这不是我的代码。

谢谢。

查尔斯。

4

3 回答 3

3

发送对象的流需要为您提供它将发送的字节数。当您读取指定的字节数时,您将知道您已完成读取对象。

于 2012-06-14T15:48:24.503 回答
2

你为什么要从套接字读取字节?只需将 ObjectInputStream 直接附加到套接字并读取对象即可。

于 2012-06-14T22:39:18.267 回答
0

好吧,IPWorks IPPortS (SSL) 类对于我需要它的几乎所有其他实例都非常有用。它使 SSL 通信变得轻而易举……就像 4 行代码和几个事件处理程序。一个问题是从流中读取对象。我没有使用 ssl 套接字实现自己的解决方案,而是实现了自己的输入流。希望有一天这对其他人有用。

输入流类:

class NetworkInputStream extends InputStream {
  private int m_Offset = 0;  
  private ByteArrayOutputStream m_Buffer = null;

  Ipports m_Ipports = null;
  public NetworkInputStream(Ipports ipport) {
    m_Ipports = ipport;
    m_Buffer = new ByteArrayOutputStream();
    try { m_Ipports.receiveStream(m_Buffer); } catch (Exception e) {}
    m_Offset = 0;
  }
  public void waitForData() throws Exception {  
    if (dataAvailable() == 0) { 
      m_Buffer.reset();
      m_Offset = 0;
    }
    while (dataAvailable() == 0 && m_Ipports.isConnected()) {      
      m_Ipports.doEvents();
    }
  }
  private int dataAvailable() {
    return m_Buffer.size() - m_Offset;  
  }
  public int read(byte[] buffer, int offset, int length) throws IOException, IndexOutOfBoundsException {
    try {
      waitForData();
    } catch (Exception e) { 
      throw new IOException(e.getMessage()); }
    int bytesRead = -1;
    int dataAvailable = dataAvailable();
    if (dataAvailable > 0) {
      bytesRead = Math.min(dataAvailable, length);
      m_Buffer.toByteArray();
      System.arraycopy(m_Buffer.toByteArray(), m_Offset, buffer, offset, length);      
      m_Offset += bytesRead;
    }
    return bytesRead;
  }
  @Override
  public int read() throws IOException {
    byte[] buf  = new byte[] { 0x00 };
    int rval = read(buf, 0, 1);
    if (rval == -1) return rval;
    int cast = (int)buf[0] & 0xff;
    return cast;
  }
}

用法:

m_Ipports.setSSLStartMode(Ipports.sslImplicit);
m_Ipports.setTimeout(60);
m_Ipports.setRemoteHost(host);
m_Ipports.setRemotePort(port);
m_Ipports.setConnected(true);

NetworkInputStream nis = new NetworkInputStream(m_Ipports);
m_Ipports.setAcceptData(true);
m_Ipports.send(dataToSend);   
ObjectInputStream ois = new ObjectInputStream(nis);
Object resp = ois.readObject();
m_Ipports.setAcceptData(false);
m_Ipports.setReceiveStream(null);
Map m = (Map)o;        

我省略了 IPPortS 的事件处理程序,您真正需要的唯一一个是:

  public void SSLServerAuthentication(IpportsSSLServerAuthenticationEvent e) {
    e.accept = true;
  }

现在,这假设您将获得一个完整的对象来响应请求。这就是我与之交互的服务器的工作方式。

查尔斯。

于 2012-06-19T20:58:29.603 回答