2015-12-02 110 views
0

我是新的Java套接字,我見過這麼多的例子,但我不明白如何將參數從服務器傳遞到客戶端,反之亦然。我的目標是傳遞一個對象,這就是爲什麼我使用對象I/O流。如何在Java服務器客戶端通過套接字傳遞對象

我必須分類服務器和播放器。

public class Server extends Thread{ 
public static final int TEST = 165; 

ServerSocket serverSocket; 
InetAddress address; 

Player playerWhite; 

public Server() {    
    start(); 
} 

@Override 
public void run() { 
    try 
    { 
     address = InetAddress.getLocalHost(); 
     serverSocket = new ServerSocket(6000); 
     playerWhite = new Player(); 

     System.out.println("server waits for players"); 
     playerWhite.socket = serverSocket.accept(); 
     playerWhite.start(); 
     sendTestMessage(playerWhite); 

    } 
    catch (IOException ex) 
    { 
     Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex); 
    }    
} 

public void sendTestMessage(Player player) throws IOException 
{ 
    ObjectOutputStream testToClient = new ObjectOutputStream(player.socket.getOutputStream());   
    testToClient.write(TEST); 
    testToClient.flush();   
} 

和玩家等級:

public class Player extends Thread { 
Socket socket; 

Player() throws IOException 
{ 
    socket = new Socket(InetAddress.getLocalHost(), 6000); 
} 

@Override 
public void run() { 
    try {    
     listenTestStream(); 
    } 
    catch (IOException | ClassNotFoundException ex) 
    { 
    Logger.getLogger(CheckerPlayer.class.getName()).log(Level.SEVERE, null, ex); 
    } 
} 

public void listenTestStream() throws IOException, ClassNotFoundException 
{ 
    ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); 
    int message = ois.readInt(); 

    //To test 
    System.out.println("Server listened: " + message); 
} 

我執行它作爲其他類中創建一個服務器對象。

當我測試這個應用程序時,我看到有時客戶端比服務器更快。是否有可能讓他「等待」服務器響應? 感謝您的回覆。

編輯1:題解:

從外面,我們應該創建:

Player player = new Player(); // (class player extends from Thread) player.start();

,並刪除播放器變量 - 是沒有必要的,我們只需要插座這樣: 服務器:

Socket playerWhiteSocket

public void run() { 
try 
{ 
    serverSocket = new ServerSocket(PORT); 
    playerWhiteSocket = serverSocket.accept(); 
    sendMessage(playerWhiteSocket, "Hello"); 
} 
catch(IOException | ClassNotFoundException ex) 
{} 

public void sendMessage(Socket socket, String message) throws IOException 
{ 
    ObjectOutputStream testToClient = new ObjectOutputStream(socket.getOutputStream());   
    testToClient.writeObject(message); 
    testToClient.flush();   
} 

在播放器類,則需要獲得方法:

public String receiveMessage() throws IOException, ClassNotFoundException 
{ 
    //socket is a variable get from Player class socket = new Socket("severHost", PORT); 
    ObjectInputStream messageFromServer = new ObjectInputStream(socket.getInputStream()); 
    String message = (String) messageFromServer.readObject(); 
    return message; 
} 
+0

您使用'write'寫入一個字節,並且應該通過'read()'接收。但是你'readInt()'。嘗試'writeInt'而不是'write'。另外,你爲什麼要發送對象?似乎是浪費帶寬。只需發送所需的數據。在從輸入流讀取數據時等待數據是自動的。 –

+0

我想發送一個「移動」類對象,我試圖先用int來完成,但是你的迴應沒有解決問題。 – rudald

+0

一般來說,你應該避免在java多線程中擴展Thread類:http://stackoverflow.com/questions/541487/implements-runnable-vs-extends-thread – avgvstvs

回答

0

是的它是。

,如果你把它放在一個endlees循環一樣,它應該工作:

try 
{ 
    while(true){ 
     address = InetAddress.getLocalHost(); 
     serverSocket = new ServerSocket(6000); 
     playerWhite = new Player(); 

     System.out.println("server waits for players"); 
     playerWhite.socket = serverSocket.accept(); 
     playerWhite.start(); 
     sendTestMessage(playerWhite); 
    } 

} 
catch (IOException ex) 
{ 
    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex); 
} 

但我不會建議把這個線程。相反,我會把一個新的客戶的一個線程的連接,以便多個客戶端可以連接到服務器

+0

我把「while」放在serverSocket之後,因爲是「Address already正在使用」。我有其他異常「文件結束異常」 - 在行ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());看來在這個套接字裏面是空的,而且參數沒有傳遞 – rudald

1

我會電子書籍這樣公共無效的start(){

try { 
     ServerSocket = new ServerSocket(this.port,10,this.localAddress); 

     // set timeout if you want 
     //this.clientServerSocket.setSoTimeout(timeout); 
     // infinity loop 
     while(true) 
     { 
      //wait for a client connection 
      Socket socket = ServerSocket.accept(); 
      // start thread for every new client 
      Thread t = new Thread(new AcceptClients(this.socket)); 
      t.start(); 
      System.out.println(L"new client connected"); 
      // call garbage collector and hope for the best 
      System.gc(); 
     } 
    } catch (IOException e) { 
     System.out.println("IO Error"); 
     e.printStackTrace(); 
    } 
} 

,然後在另一個類

public class AcceptClients implements Runnable{ 

// socket 
private Socket socket; 

public AcceptClients (Socket socket){ 
    this.socket = socket; 
} 
@Override 
public void run() { 
    // what happens if a client connect 
} 

}

我一直用這個,它工作正常

1

建議的更改。

  1. 創建ServerSocket只有一次。如果你已經完成了,你將不會得到「Address already in use」錯誤

  2. 創建服務器套接字後,你的線程應該在while (true)循環中接受來自客戶端的連接。

  3. 創建客戶端套接字後,將該套接字傳遞給線程。

  4. Now Player用於發送從服務器到客戶端套接字的通信。因此,您需要另外一個類,例如PlayerClient,它們會爲服務器IP和端口創建一個套接字。現在,PlayerClient應該創建一個線程來處理IO操作,就像你從服務器完成的那樣。在這種情況下,創建套接字不在客戶端的while循環中。它創建一次到服務器的套接字。現在你可以從多臺機器上運行這個PlayerClient程序。

  5. 如果你只是只發送原始類型,用DataOutputStream & DataInputStream代替ObjectStreams

此代碼將變成這個樣子

try 
    { 
     address = InetAddress.getLocalHost(); 
     serverSocket = new ServerSocket(6000); 
     System.out.println("server waits for players"); 

     while (true){ 
      Socket socket = serverSocket.accept(); 
      Player playerWhite = new Player(socket); 
      sendTestMessage(socket);// Move this method to Player thread and change the signature of this method accordingly to accept a socket 
     } 

    } 
    catch (IOException ex) 
    { 
     Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex); 
    }  

Player.java

Player(Socket socket) throws IOException 
{ 
    this.socket = socket; 
    start(); 
} 

有看看這個chat的例子可以更好地理解。

相關問題