2009-01-22 81 views
2

我用java插座構建一個簡單的客戶端/服務器應用程序,並與用ObjectOutputStream試驗等的Java socket編程

我一直在這個網址http://java.sun.com/developer/technicalArticles/ALT/sockets教程開始一半時以下時,談到了運輸物件插座。

看我的客戶端代碼http://pastebin.com/m37e4c577但是,這似乎並沒有工作,我不明白什麼是行不通的。在底部註釋掉的代碼直接從教程中複製出來 - 這在我剛剛使用該代碼而不是創建客戶端對象時起作用。

任何人都可以看到我做錯了什麼嗎?

+0

您需要取消註釋。哈認真,但編譯錯誤是什麼? – 2009-01-22 23:53:44

+0

有沒有錯誤 - 它只是不工作與我未註釋的代碼,我不明白爲什麼?評論代碼的作品 - 我剛分離,並把它放到一個實際的對象......這讓我發瘋。 – Malachi 2009-01-23 08:22:52

回答

7

問題是你所創建的數據流的順序:

在文章的服務器中(我假設您正在使用的是),當打開一個新連接時,服務器首先打開輸入流,然後打開輸出流:

public Connect(Socket clientSocket) { 
client = clientSocket; 
try { 
    ois = new ObjectInputStream(client.getInputStream()); 
    oos = new ObjectOutputStream(client.getOutputStream()); 
} catch(Exception e1) { 
    // ... 
} 
this.start(); 
} 

註釋的示例代碼使用了相反的順序,首先建立輸出流,然後輸入流:

// open a socket connection 
socket = new Socket("localhost", 2000); 
// open I/O streams for objects 
oos = new ObjectOutputStream(socket.getOutputStream()); 
ois = new ObjectInputStream(socket.getInputStream()); 

但是你的代碼做它周圍的其他方法:建立一個輸出流

server = new Socket(host, port); 
in = new ObjectInputStream(server.getInputStream()); 
out = new ObjectOutputStream(server.getOutputStream()); 

/輸入流對將停止,直到他們交換了握手信息,所以您必須匹配創建順序。您可以通過在示例代碼中交換第34行和第35行來完成此操作。

5

你不在任何地方寫對象。

再看到該鏈接,地方你必須寫:

oos.writeObject(new Date()); 

在你的代碼只有

ois.readObject(); 

這就是爲什麼

+0

發佈的代碼僅包含客戶端,因此不需要編寫對象。 – 2009-01-23 17:55:55

1

也許你會喜歡學習最基本第一。

下面是我剛剛編碼的示例。

它開始服務器,只出席一個客戶端,它發送一個對象和死亡。

當用戶(你)按回車鍵時,會創建一個新的客戶端,它會連接到先前創建的服務器並讀取服務器將發送的對象。

這裏沒有例外。只是爲了簡化事情,但這不是應該處理異常的方式。

當你理解了這裏的所有概念時,會更容易理解教程中的那些概念。

import java.io.*; 
import java.net.*; 
import java.util.*; 

public class SimpleServer implements Runnable { 

    // Creates the server, send a "date" and die. 
    public void run() { 
     try { 
      ServerSocket server = new ServerSocket(8090); 
      Date creationDate = new Date(); 
      System.out.println("(Server) Server is ready " 
           + "and running at " + creationDate); 

      Socket uniqueClient = server.accept(); 

      // We will write using this "chained" object. 
      ObjectOutputStream out = new ObjectOutputStream( 
               uniqueClient.getOutputStream()); 

      out.writeObject(creationDate); 


      // close all, at this point forget about the exceptions. 
      // this is lesson #1  
      out.close(); 

      uniqueClient.close(); 

      server.close();   

      System.out.println("(Server) The server is down"); 
     }catch(IOException ioe) {} 

    } 

    public static void main (String [] args) throws IOException , 
               ClassNotFoundException { 

     Thread serverThread = new Thread(new SimpleServer()); 

     serverThread.start(); // start the server thread ... doh.. 

     System.out.println("(Client) Press enter when you want "+ 
           " to connect to the server..."); 

     Scanner scanner = new Scanner(System.in); 

     scanner.nextLine(); 

     Socket client = new Socket("localhost", 8090); 

     // Read from this object. 
     ObjectInputStream in = new ObjectInputStream(client.getInputStream()); 

     Date date = (Date) in.readObject(); 

     System.out.println("(Client) Current time is:   " + new Date()); 
     System.out.println("(Client) Object read from server : " + date); 

     in.close(); 
     client.close(); 

    } 
} 

我希望這會有所幫助。

1

如果您嘗試調試它會告訴你哪裏出了問題了。(也許不是爲什麼)

你的問題是,ObjectOutputStream中寫一個標題和ObjectInputStream的讀取頭。您首先創建了ObjectInputStream,這意味着它正在嘗試讀取永遠不會寫入的標題。

解決方案:始終首先創建ObjectOutputStream並在創建ObjectInputStream之前flush()它。

2

只是提醒。

當您使用ObjectOutputStream時請記住它保留了一個引用緩存。如果您編寫一個對象,更改對象內容,然後再次發送相同的對象,您將獲得重複的數據。例如:

List list = new ArrayList(); 
list.add("value1"); 
out.writeObject(list); 
list.clear(); 
list.add("value2"); 
out.writeObject(list); 

將在客戶端產生兩個帶有字符串「value1」的列表。

爲了避免這種情況,復位方法必須調用同一個對象的引用多次寫入時重置流緩存:

List list = new ArrayList(); 
list.add("value1"); 
out.writeObject(list); 
out.reset(); 
list.clear(); 
list.add("value2"); 
out.writeObject(list); 
1

最好打開一個outputStream,因爲輸出流不會阻塞。然後,您有輸入流等待Stream。在所有的流之後,你寫入流並刷新它 - outputStream.flush()發送數據的字節。您還需要在另一端讀取輸入的方法,無論是簡單的inputStream.read(),它將每個字節讀取爲char的整數或使用BufferedReaderScanner。我已經使用了幾乎所有可能的方法,但最有效的發送方法是outputStream.write(String),它將char s的序列作爲byte s寫入流中,並且閱讀inputStream.read()讀取單個char。我希望這有幫助。