2010-12-05 51 views
4

我一直在試圖調試2小時,我無法解釋它。 我有一臺服務器和一個客戶端。 (服務器管理一些拍賣)。Java套接字 - 接收但未發送的內容!

會發生什麼:

  1. 客戶端請求的東西,服務器將數據發送回客戶端接收它就好了。

  2. 客戶端發送一些東西給服務器,服務器更新一些數據。

  3. 客戶端發出的第一時間(1),服務器發回更新 數據相同的請求,但客戶沒有收到新的更新數據,而是接收的舊數據(因爲它有它在

正在發送數據的第一個請求(1)只是一個Java Bean有兩個List-S 和代碼:

// CLIENT CLASS 
// creates socket, sends and listens on the socket 
// listening is done on a separate thread 
public class ServerConnector { 

private Socket socket = null; 
private ObjectOutputStream out = null; 
private Display display; 
private ServerListener listener; 
public ServerConnector(Display display) { 
    this.display = display; 
     try { 
      socket = new Socket("localhost",33333); 
      out = new ObjectOutputStream(socket.getOutputStream()); 
     } catch (UnknownHostException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     listener = new ServerListener(socket, display); 
     new Thread(listener).start(); 


} 



public void sendRequest(Request request) { 
    try { 
     out.writeObject(request); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

} 

class ServerListener implements Runnable { 
    private Socket socket; 
    private ObjectInputStream in = null; 
    private Display display; 
    public ServerListener(Socket socket,Display display) { 
     this.socket = socket; 
     this.display = display; 
     try { 
      in = new ObjectInputStream(socket.getInputStream()); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
    @Override 
    public void run() { 
     Response response =null; 

     try { 
      while ((response = (Response)in.readObject()) != null) { 
       if (response.getCars().size() > 0) { 
        display.showAvailableCars(response.getCars()); 
       } 
       if(response.getAucs().size() > 0) { 
        List<Auction> auctionz = response.getAucs();//HERE 1st time it gets the GOOD data, 2nd time should get UPDATED DATA but instead receives the OLD DATA (same as 1st time). 
        display.showOpenAuctions(auctionz); 
       } 
       response = null; 
      } 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (ClassNotFoundException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

    } 

} 

} 
//CLIENT CLASS 
// controls when something should be sent, and print out responses 
public class Display { 
Scanner console = new Scanner(System.in); 
ServerConnector server = new ServerConnector(this); 
List<Car> cars; 
List<Auction> aucs; 

public void show() { 
    int opt = 0; 
     System.out.println("1. Show available cars for auction."); 
     System.out.println("2. Show open auctions."); 
     opt = console.nextInt(); 
     Request request = new Request(); 
     if (opt == 1) 
      request.setRequest(Request.GET_CARS); 
     if (opt == 2) { 
      request.setRequest(Request.GET_OPEN_AUCTIONS); 
     } 
     server.sendRequest(request); 

    } 


public void showAvailableCars(List<Car> cars) { 
    int i = 0; 
    for (Car c : cars){ 
     i++; 
     System.out.println(i +". " + c.getMaker() + " " + c.getModel() + " price: " + c.getPrice()); 
    } 
    System.out.println("Select car to open Auction for:"); 
    int selectedCar = console.nextInt(); 
    if (selectedCar != 0) { 
     if (selectedCar <= cars.size()) { 
      Request request= new Request(); 
      request.setRequest(Request.OPEN_AUCTION); 
      Car c = cars.get(selectedCar-1); 
      request.setCar(c); 
      server.sendRequest(request); 
     } 
    } 
    show(); 
} 


public void setCars(List<Car> cars) { 
    this.cars = cars; 

} 


public void showOpenAuctions(List<Auction> aucs2) { 
    int i = 0; 
    for (Auction auc : aucs2) { 
     i++; 
     System.out.println(i+ ". " + auc.getCar().getModel() + " " + auc.getCar().getMaker() + " last price: " + auc.getPrice()); 
    } 
    System.out.println("You can now make offers"); 
    System.out.println("Input auction number:"); 
    int selectedAuction = 0; 
    selectedAuction = console.nextInt(); 
    if (selectedAuction > 0 && selectedAuction <= aucs2.size()) { 
     System.out.println("Offer new price:"); 
     int price = console.nextInt(); 
     Request request= new Request(); 
     request.setRequest(Request.MAKE_OFFER); 
     request.setAuctionId(aucs2.get(selectedAuction-1).getId()); 
     request.setPrice(price); 
     server.sendRequest(request); 
    } 
    show(); 

} 


public void setOpenAuctions(List<Auction> aucs2) { 
    this.aucs = aucs2; 

} 

} 
// SERVER CLASS : send and receives 
public class ClientManager implements Runnable { 

private AuctionManager manager = new AuctionManagerImpl(); 
private Socket client; 
private ObjectInputStream in = null; 
private ObjectOutputStream out = null; 


public ClientManager(Socket socket) { 
    this.client = socket; 
    try { 
      in = new ObjectInputStream(client.getInputStream()); 
      out = new ObjectOutputStream(client.getOutputStream()); 
    } catch(Exception e1) { 
      try { 
       e1.printStackTrace(); 
       client.close(); 
     }catch(Exception e) { 
       System.out.println(e.getMessage()); 
      } 
      return; 
     } 
} 

@Override 
public void run() { 
    Request req = null; 
    try { 
      while ((req = (Request)in.readObject()) != null) { 
       if (req.getRequest() != null) { 
        if (req.getRequest().equals(Request.GET_CARS)) { 
         Response response = new Response(); 
         response.setCars(manager.getAvailableCars()); 
         out.writeObject(response); 
         continue; 
        } 

        if (req.getRequest().equals(Request.OPEN_AUCTION)) { 
         manager.openAuction(req.getCar()); 
         continue; 
        } 

        if (req.getRequest().equals(Request.GET_OPEN_AUCTIONS)) { 
         Response response = new Response(); 
         response.setAucs(manager.getHoldedAuctions()); //this line ALWAYS sends to the client GOOD, UPDATED DATA 

         out.writeObject(response); 
         out.flush(); 
         continue; 
        } 
        if (req.getRequest().equals(Request.MAKE_OFFER)) { 
         Auction auction = manager.getOpenAuction(req.getAuctionId()); 
         manager.updateAuction(auction, req.getPrice(),client.getRemoteSocketAddress().toString()); 
         continue; 
        } 
      } 
     } 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (ClassNotFoundException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

} 

} 

回答

3

可能是因爲您正在使用ObjectOutputStreams。請記住,ObjectOutputStreams將緩存寫入它們的所有對象,以便如果將來再次寫入同一個對象,它可以寫入後向引用而不是重寫整個對象。編寫對象圖時這是必需的。

您的代碼片段:

if (req.getRequest().equals(Request.GET_CARS)) { 
    Response response = new Response(); 
    response.setCars(manager.getAvailableCars()); 
    out.writeObject(response); 
    continue; 
} 

在寫一部manager.getAvailableCars()返回的對象。下一次接收到請求時,會寫入同一個對象(但現在具有不同的內容) - 但ObjectOutputStream不知道新內容,因此它只是寫入反向引用。在另一端的ObjectInputStream看到後向引用並返回它上次讀取的同一對象,即原始數據。

您可以在每次回覆後通過撥打ObjectOutputStream.reset()來解決此問題。這將清除流的緩存。

2

見ObjectOutputStream.writeUnshared( )和.reset()。

0

好的。我剛剛發現瞭解決方案。 從這裏http://java.sun.com/developer/technicalArticles/ALT/sockets/

對象序列化陷阱

當使用對象序列化工作是要記住的是,ObjectOutputStream中保持哈希表映射寫進流的句柄的對象是很重要的。當一個對象第一次被寫入流時,其內容將被複制到流中。然而,後續的寫操作會導致正在寫入流的對象的句柄。這可能會導致幾個問題:

如果一個對象被寫入流中,然後再次修改並寫入,那麼當流被反序列化時,修改將不會被注意到。同樣,原因是隨後的寫入會導致正在寫入的句柄,但修改後的對象不會被複制到流中。爲了解決這個問題,調用ObjectOutputStream.reset方法,該方法放棄發送對象的內存,以便隨後的寫入將對象複製到流中。 將大量對象寫入ObjectOutputStream後,可能會引發OutOfMemoryError。其原因是散列表保持對應用程序可能無法訪問的對象的引用。只需調用ObjectOutputStream.reset方法將對象/句柄表重置爲其初始狀態即可解決此問題。在這次調用之後,所有以前編寫的對象都有資格進行垃圾回收。 重置方法將流狀態重置爲與剛剛構建的狀態相同。當對象被序列化時,可能不會調用此方法。此方法的不適當的調用會導致IOException。