2014-04-28 121 views
1

我寫了一個runnable網絡類,它在套接字上偵聽並取消編組輸入。它也可以使用編組對象寫入套接字。出現問題是因爲套接字保持打開狀態(以便稍後允許客戶端和主機之間的通信) - 這會導致輸入流的解組停止。我已經嘗試從發件人一方編寫XMLStreamConstants.END_DOCUMENT,但這會導致錯誤解組而不是掛起。下面是一些對網絡類代碼:Unmarshalling掛在打開套接字上

@Override 
public void update(Observable o, Object arg) { 
    try { 
     if(!this.updatedByNetwork){ 
      OutputStream os = socket.getOutputStream(); 
      mh.marshal(this.gm.getBoard(), os); 
      os.flush(); 
     } 
    }catch (IOException e) { 
     e.printStackTrace(); 
    } catch (JAXBException e) { 
     e.printStackTrace(); 
    } 
} 
@Override 
public void run() { 
    try { 
     if (this.ss != null){ 
      this.socket = this.ss.accept(); 
      this.update(this.gm, null); 
     } 
     while (true){ 
      try { 
       InputStream is = socket.getInputStream(); 
       Board b = mh.unmarshal(is); 
       this.updatedByNetwork = true; 
       this.gm.updateBoard(b); 
      } catch (SocketTimeoutException e){ 
       e.printStackTrace(); 
      } catch (JAXBException e) { 
       e.printStackTrace(); 
      } 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

下面的代碼爲我的馬歇爾處理程序:

public Board unmarshal(InputStream in) throws JAXBException{ 
     Unmarshaller um = this.jc.createUnmarshaller(); 
     Board b = (Board) um.unmarshal(in); 
     return b; 
} 
public void marshal(Board b, OutputStream os) throws JAXBException { 
     Marshaller m = this.jc.createMarshaller(); 
     m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     m.marshal(b, os); 
} 

那麼,有沒有一種方法來表示文件的解組結束了嗎?或者,有沒有更好的方法來做到這一點?

回答

1

即使有一種方法可以向解組器發送「文件結束」信號,但當兩個或更多個消息彼此直接發送時,解組器仍可能會讀取下一條消息。爲了防止這種情況的發生,網絡協議層需要到位,從邏輯上將發送/接收的字節分隔成不同的消息。在下面的示例中,該「協議」在writeMsgreadMsg方法中實施。請注意,這是一個簡單的例子,假設所有消息都可以在內存中完全處理。

import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.DataInputStream; 
import java.io.DataOutputStream; 
import java.net.InetAddress; 
import java.net.ServerSocket; 
import java.net.Socket; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.Marshaller; 
import javax.xml.bind.Unmarshaller; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement 
public class NetworkMarshall { 

private static final int NumberOfMsgs = 2; 

public static void main(String[] args) { 

    Socket s = null; 
    try { 
     JAXBContext jc = JAXBContext.newInstance(NetworkMarshall.class); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     Unmarshaller unmarshaller = jc.createUnmarshaller(); 

     new Thread(new Receiver(unmarshaller)).start(); 
     // Wait for socket server to start 
     Thread.sleep(500); 
     s = new Socket(InetAddress.getLocalHost(), 54321); 
     DataOutputStream dos = new DataOutputStream(s.getOutputStream()); 

     for (int i = 0; i < NumberOfMsgs; i++) { 
      NetworkMarshall msg = new NetworkMarshall(); 
      msg.setName("vanOekel" + i); 
      writeMsg(msg, marshaller, dos); 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } finally { 
     try { s.close(); } catch (Exception ignored) {} 
    } 
} 

private static void writeMsg(NetworkMarshall msg, Marshaller marshaller, DataOutputStream dos) throws Exception { 

    ByteArrayOutputStream bout = new ByteArrayOutputStream(); 
    marshaller.marshal(msg, bout); 
    byte[] msgBytes = bout.toByteArray(); 
    System.out.println("Sending msg: " + new String(msgBytes)); 
    dos.writeInt(msgBytes.length); 
    dos.write(msgBytes); 
    dos.flush(); 
} 

private String name; 

public void setName(String name) { 
    this.name = name; 
} 

public String getName() { 
    return name; 
} 

public String toString() { 
    return this.getClass().getName() + ": " + getName(); 
} 

static class Receiver implements Runnable { 

    final Unmarshaller unmarshaller; 

    public Receiver(Unmarshaller unmarshaller) { 
     this.unmarshaller = unmarshaller; 
    } 

    public void run() { 

     ServerSocket ss = null; 
     Socket s = null; 
     try { 
      s = (ss = new ServerSocket(54321)).accept(); 
      DataInputStream dis = new DataInputStream(s.getInputStream()); 
      for (int i = 0; i < NumberOfMsgs; i++) { 
       Object o = unmarshaller.unmarshal(readMsg(dis)); 
       System.out.println("Received message " + i + ": " + o); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } finally { 
      try { ss.close(); } catch (Exception ignored) {} 
      try { s.close(); } catch (Exception ignored) {} 
     } 
    } 

    private ByteArrayInputStream readMsg(DataInputStream dis) throws Exception { 

     int size = dis.readInt(); 
     byte[] ba = new byte[size]; 
     dis.readFully(ba); 
     return new ByteArrayInputStream(ba); 
    } 
} 
}