2013-04-24 76 views
0

心中已經得到了其使用多線程發送對象ServerSocket的代碼(目前localy,但在本地網絡的未來)Java的插座ObjectOutputStream的多線程

用於發送對象:

public class SocketToAdapter { 

public static void writeObject(Object object) { 
    try { 

     give().writeUnshared(object); 

    } catch (IOException e) { 
     System.out.println(e.getMessage()); 
    } 
} 

static ObjectOutputStream give() { 
    Socket s = null; 
    try { 
     s = new Socket("localhost", 9990); 
     s.setTcpNoDelay(true); 
     return new ObjectOutputStream(s.getOutputStream()); 

    } catch (UnknownHostException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    return null; 
} 

主要方法:

SocketToAdapter soc = new SocketToAdapter(); 

    thread1.setSocket(soc); 
    thread2.setSocket(soc); 
    thread3.setSocket(soc); 
    thread4.setSocket(soc); 
    thread5.setSocket(soc); 

    synchronized (valueExchanging) { 
     synchronized (soc) { 
      thread1.start(); 
      thread2.start(); 
      thread3.start(); 
      thread4.start(); 
      thread5.start(); 
     } 

valueExchanging是用於beetwen線程交換數據的對象。

從線程運行方法:

public void run() { 
    try { 
     while (true) { 
      curr = new Object(pair, RandomUtil.getRandomExchange(), 
        RandomUtil.getRandomTurn()); 
      //not important Business Logic. 
          int v1 = valueExchanger.getExchangeInTread()+1; 
      int v2 = valueExchanger.getExchangeInTread()-100; 
      curr = new Object(pair, BigInteger.valueOf(v1), 
        BigInteger.valueOf(v2)); 
          // 
      SocketToAdapter.writeObject(curr); 
      valueExchanger.setExchangeInTread(v1); 
      Thread.sleep(0, 1); 
     } 
    } catch (InterruptedException iex) { 
    } 
} 

這一工程,但速度很慢。因爲每次需要時都會創建Socket和ObjectOutputStream。我嘗試創建一個Socket和一個OOS和使用它像這樣:

    { 
     Socket s = new Socket("localhost", 9990); 
     ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream()); } 

然後

oos.writeUnshared(object); 
oos.flush(); 
oos.writeUnshared(object); 

,但如果我嘗試重用OOS我第二次獲得軟件導致連接中止:套接字寫入錯誤。無論我使用多少線程。

我需要什麼可以發送許多(例如100k)對象每秒,任何sugesstions?

在服務器端我做的:

Serwer.java:

ServerSocket ss; 
public static void pre()throws IOException, ClassNotFoundException { 
    ss = new ServerSocket(9990); 
    } 

public static Object start() throws IOException, ClassNotFoundException { 
    Object o = null; 
    Socket s = ss.accept(); 
    while (!s.isClosed()) { 
     ObjectInputStream ois = new ObjectInputStream(s.getInputStream()); 
     o = (Object) ois.readObject(); 
     ois.close(); 
     s.close(); 
    } 
    ss.close(); 
    return o; 

} 

「主要方法」

while (true) { 

      try { 
       Serwer.pre(); 
       Object o = Serwer.start(); 
            //im do somethink with that object o. 
      } catch (IOException e1) { 
       e1.printStackTrace(); 
      } catch (ClassNotFoundException e) { 
       e.printStackTrace(); 
      } 
     } 
+0

爲什麼在啓動線程時同步soc?當使用來自多個線程的資源時,您必須在資源上進行同步。並保持同步塊的簡短。甚至不嘗試相處。同步是一個巨大的性能殺手。 – Fildor 2013-04-24 15:07:21

+0

目前不是同步問題(即使我使用一個沒有同步的線程,性能很糟糕)。 – user1055201 2013-04-24 15:12:46

+0

你一定要爲你的設計帶來更多的結構。沒有冒犯,但儘量不要在一個地方做太多事情...... – Fildor 2013-04-24 17:12:42

回答

0

你是否在9990服務器讀取對象後,關閉連接,或它失敗了嗎?

在此之後整理出來,你可以看看利用快速的對象序列化一樣kryo

1

在它的開放爲發送每個對象一個新的TCP連接的客戶端優化速度系列化。這會導致性能下降,因爲建立TCP連接需要大量開銷。

從您的代碼看,服務器看起來像是在處理完一個對象後關閉連接。在處理一個似乎完全不起作用的連接後,它也關閉了ServerSocket。服務器代碼是否正確?服務器代碼中是否有另一個循環會啓動另一個ServerSocket

最好的方法可能是讓每個客戶端線程創建自己的Socket,每個客戶端都有一個到服務器的單獨連接。如果您試圖推送大量數據並使用多線程來實現此目標,那麼服務器很可能需要多個線程來處理數據。這些套接字應該創建一次並重用來發送所有對象。

在服務器端,您將需要創建一個適當的多線程TCP服務器。這裏的一般想法是創建一個SocketServer並在while循環中調用其accept()方法。對於從accept()返回的每個Socket,您將啓動一個新線程來處理請求。一個例子可以在這裏找到:Multithreaded Server using TCP in Java

+0

我稱之爲「主要方法」有一個循環 – user1055201 2013-04-24 17:03:39

+0

你知道你可以循環接受accept()而不是整個serversocket創建?你甚至可以處理多個連接simultanoulsy產生一個線程爲每個插座,你可以通過下一個接受... – Fildor 2013-04-24 17:08:18

0

我沒有經驗的java套接字,但由行s.setTcpNoDelay(true);我假設你的程序使用tcp發送數據包,請嘗試使用udp。 tcp協議是爲了保證數據包到達目的地,並且要做到這一點,一旦它們到達,它必須驗證完整性。另一方面udp不會這樣做,它只發送數據包而不關心完整性,這就是爲什麼在線多人遊戲使用它。

+0

我如何使用UDP而不是TCP? – user1055201 2013-04-24 17:02:10

+0

@ user1055201這是一個完全不同的故事。也許這會有所幫助:http://systembash.com/content/a-simple-java-udp-server-and-udp-client/ – Fildor 2013-04-24 17:06:23

1

我有同樣的問題,並通過使用一個簡單的包裝類爲我的套接字解​​決了它。 此類的對象必須存在於需要讀/寫操作的任何點。

public class Sender implements Closeable 
{ 
    private final Socket sock; 
    private final ObjectOutputStream out; 
    private ObjectInputStream in = null; 

    private final Object oLock = new Object(); 
    private final Object iLock = new Object(); 

    //optional 
    public boolean isClosed(){ 
    return sock.isClosed(); 
    } 

    //there is a better way to do this 
    public Socket getSocket(){ 

    return sock; 
    } 

    //use this to send data 
    public void send(Object o) throws IOException { 
    synchronized (oLock){ 
     getOOS().writeObject(o); 
    } 
    } 

    //use this to read data 
    public Object get() throws IOException { 
    synchronized (iLock){ 
     return getOIS().readObject(); 
    } 
    } 

    private ObjectOutputStream getOOS() { 
    return out; 
    } 

    //not the best way... but wouldn't work otherwise 
    private ObjectInputStream getOIS() throws IOException { 
    if(in == null) 
     in = new ObjectInputStream(sock.getInputStream()); 
    return in; 
    } 

    public Sender(Socket s) throws IOException { 
    sock = s; 
    out = new ObjectOutputStream(s.getOutputStream()); 
    //in = new ObjectInputStream(s.getInputStream()); 
    //getting the input and output stream gave me some weird deadlock 
    } 

    //optional 
    @Override 
    public String toString() { 
    return sock.toString(); 
    } 

    //flush and close if sock is not yet closed 
    @Override 
    public void close() throws IOException { 
    if(!sock.isClosed()){ 
     if(out != null) 
      out.flush(); 

     sock.close(); 
    } 
    } 
} 

這一個運作良好,並在快速客戶端(Sender是連接到服務器的插槽)和 服務器(發件人是連接到客戶端的套接字)。

希望這會有所幫助。

Greet roop