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을 읽고 있어요 그래서, 내 질문은, 어떻게 내가 개체의 끝에 도달 한 결정합니까?

참고 : 이러한 개체를받는 서버를 어떤 식 으로든 수정할 수는 없습니다. 그건 내 코드가 아니야.

감사합니다.

찰스.

+0

http://docs.oracle.com/javase/6/docs/api/java/io/ObjectInputStream.html – blank

답변

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; 
    } 
} 

: 나는 IPPortS에 대한 이벤트 핸들러를 생략 한

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;   

은, 당신이 정말로 필요로하는 단 하나입니다 : 이제

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

, 이것은 요청에 응답하여 하나의 완전한 객체를 얻을 것이라고 가정합니다. 이것이 내가 작동하는 서버가 작동하는 방식입니다.

찰스.

3

개체를 보내는 스트림에서 보낼 바이트 수를 제공해야합니다. 지정된 바이트 수를 읽었을 때 객체 읽기를 완료했음을 알 수 있습니다.

+0

+1 또 다른 이유는 다음 객체를위한 바이트를 읽을 수 없다는 것입니다. (그들은 무시되고 다음 객체는 손상됩니다.) –

+0

이것은 옵션이 아니며 데이터를 보내는 서버를 수정할 수 없습니다. – ChopperCharles

+0

이 예제가 작동하는지 확인하십시오 : http://www.java2s.com/Code/Java/Network-Protocol/ObjectInputStreamandObjectOutputStreamfromSocket.htm. 누군가가 연결을 끊지 않는 한 당신이 읽은 것을 어떻게 알게되는지 나는 알 수 없다. – cklab

2

왜 소켓에서 바이트를 읽는 중입니까? 소켓에 직접 ObjectInputStream을 연결하고 객체을 읽습니다.

+0

나는 그 선택권이 없기 때문에. www.nsoftware.com에서 만든 IPPort SSL 클래스를 사용하고 있습니다. 전선을 통해받은 데이터를 읽는 두 가지 방법이 있습니다. 1) 읽은 바이트를 포함하는 매개 변수와 함께 DataIn 이벤트가 발생합니다. 나는 그것이 동기 읽기가되기를 원하기 때문에 대기 루프를 입력하고 EOL을 기다린다. (하지만, 나는 지금 EOL을 가지고 있지 않다.) – ChopperCharles

+0

2) 데이터 수신시 클래스가 직접 쓰는 OUTPUT 스트림을 설정할 수 있습니다. 그 대신 ByteArrayOutputStream을 사용할 수 있습니다 ... 그러나 OUTPUT 스트림이며 readObject를 사용하여 데이터를 읽으려면 INPUT 스트림이 필요합니다. 따라서 ObjectInputStream을 사용하기 전에 바이트를 가져와 ByteArrayInputStream에 추가해야합니다. 소켓에 직접 액세스 할 수 없습니다. – ChopperCharles

+1

@ChopperCharles 그래서 * 주요 * 문제가 있습니다. ObjectInputStream에 필요한 바로 그 스트림을 감추기 위해 고안된 API를 사용하고 있습니다. 위의 Peter Lawrey가 제안한 길이 단어 접두사를 포함하도록 보내는 프로토콜을 변경하거나 다른 것을 디코딩하기 전에 EOS까지 소켓을 읽어야합니다. 인프라를 검토하는 것이 좋습니다. 도움이되기보다는 방해가되고 있습니다. 'javax.net.ssl.SSLSocket'에는 문제가 없습니다. 직렬화 된 스트림을 직접 해독하려는 계획은이 IPPort 손상으로 인한 피해가 얼마나되는지를 보여줍니다. – EJP