3

いいタイトルを考えてみましたが、失敗したようです。これが私の問題です:

ソケットからデータを読み込んでいます。バッファに含まれるデータはシリアル化されたオブジェクトです。データが完全に読み取られたら、ObjectInputStreamを作成し、readObjectを使用してデータを読み込むことができます。

私の問題は、私のソケットクラスがバイトを読み取っているので...完全なオブジェクトを受け取ったことをどのように知ることができますか?オブジェクトの終わりのインジケーターがないようです。シリアル化されたバイトコードの内訳を探して長さフィールドを見つけることができるかどうかを確認しようとしましたが、シリアル化のバイトコードはGoogleで見つけることができる場所では十分に説明されていません。

私が受け取っているオブジェクトは、違いが生じる場合はハッシュマップ(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行のコードと2つのイベントハンドラーのように。1つの問題は、ストリームからオブジェクトを読み取ることでした。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;
  }

これで、リクエストに応じて1つの完全なオブジェクトを取得することを前提としています。これが、私が対話しているサーバーの動作方法です。

チャールズ。

于 2012-06-19T20:58:29.603 に答える