2013-07-14 302 views
2

我有一個Java程序將客戶端連接到服務器。 這包括在客戶端通過發送消息觸發服務器後創建文件目錄。例如:一旦服務器已經運行,客戶端就會連接併發送msg,即「Your message:Lady」,服務器將收到一條消息,如「請求創建名爲Directory的女士:Lady」,在此之後的目錄將創建一個名爲Lady。客戶端 - 服務器連接

但問題是,這種連接是唯一一個對一個。就像只有一個客戶端可以連接到服務器...

這是示例代碼:

/* 
* To change this template, choose Tools | Templates 
* and open the template in the editor. 
*/ 
package today._; 

import java.io.*; 

import java.net.*; 

import java.text.*; 

import java.util.*; 

public class myServer { 

    protected static final int PORT_NUMBER = 55555; 

    public static void main(String args[]) { 

     try { 

      ServerSocket servsock = new ServerSocket(PORT_NUMBER); 

      System.out.println("Server running..."); 

      while (true) { 
       Socket sock = servsock.accept(); 
       System.out.println("Connection from: " + sock.getInetAddress()); 
       Scanner in = new Scanner(sock.getInputStream()); 
       PrintWriter out = new PrintWriter(sock.getOutputStream()); 
       String request = ""; 
       while (in.hasNext()) { 
        request = in.next(); 
        System.out.println("Request to Create Directory named: " + request); 

      if(request.toUpperCase().equals("TIME")) { 
        try { 
         File file = new File("C:\\" + request); 
         if (!file.exists()) { 
          if (file.mkdir()) { 
           System.out.println("Directory is created!"); 
          } else { 
           System.out.println("Failed to create directory!"); 
          } 
         } 
        } catch (Exception e) { 
         System.out.println(e); 
        } 
        out.println(getTime()); 

        out.flush(); 
      } else { 
       out.println("Invalid Request...");      
       out.flush(); 
      } 
       } 

      } 


     } catch (Exception e) { 
      System.out.println(e.toString()); 
     } 

    } 

    protected static String getTime() { 
     DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); 
     Date date = new Date(); 
     return (dateFormat.format(date)); 
    } 
} 

package today._; 

import java.io.*; 

import java.net.*; 

import java.util.*; 

public class myClient { 

     protected static final String HOST = "localhost"; 
     protected static final int PORT = 55555; 

     protected static Socket sock; 

     public static void main(String args[]) { 

     try { 

       sock = new Socket(HOST,PORT); 

       System.out.println("Connected to " + HOST + " on port " + PORT); 

       Scanner response = new Scanner(sock.getInputStream()); 
       PrintWriter request = new PrintWriter(sock.getOutputStream()); 
       BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 
       String txt = ""; 

       while(!txt.toUpperCase().equals("EXIT")) { 

        System.out.print("Your message:"); 
        txt = in.readLine(); 

        request.println(txt); 
        request.flush(); 

        System.out.println(response.next()); 

       } 

       request.close(); 
       response.close(); 
       in.close(); 
       sock.close(); 

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

} 
+2

您需要每個客戶端一個線程的服務器上。請參見本教程頁的末尾:http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html –

回答

2

多客戶端的服務器一般都寫的兩種方法之一:

  1. 創建爲每個客戶端一個線程。爲此,您可以創建一個線程來處理對服務器套接字上的accept()調用,然後生成一個新線程來處理它返回的套接字上的調用。如果你這樣做,你需要確保你儘可能地隔離每個套接字的代碼。接受線程將永遠循環,或者直到設置了一個標誌,並且只會調用accept,用新的套接字產生一個線程,然後返回到調用accept。所有的工作都在子線程中。

  2. 使用NIO,或其他技術,多路複用工作到1個更多的線程。 NIO使用一個有時稱爲select的概念,當有特定套接字的輸入時,你的代碼將被調用。

如果你只是在做一個小的服務器,你可以去用最簡單的設計,也將不會有太多的客戶,所以我會用#1去。如果你正在做一個大型的生產服務器,我會研究一下像netty或jetty這樣的框架,它可以幫助你實現#2。 NIO可能會很棘手。

在這兩種情況下,非常小心線程和文件系統,如果你不從併發包中使用一個鎖,或同步或其他鎖定方案你可能無法得到預期的結果。

我最後的忠告,要小心有客戶告訴服務器做文件系統的任何東西。只是說,那就是做;-)

1

您的服務器類必須使用多線程來處理所有連接件危險的事:

class MyServer { 


    private ServerSocket servsock; 

    MyServer(){ 
     servsock = new ServerSocket(PORT_NUMBER); 
    } 

    public void waitForConnection(){ 
     while(true){ 
      Socket socket = servsock.accept(); 
      doService(socket); 
     } 
    } 

    private void doService(Socket socket){ 
     Thread t = new Thread(new Runnable(){ 
      public void run(){ 
       while(!socket.isClosed()){ 
        Scanner in = new Scanner(sock.getInputStream()); 
        PrintWriter out = new PrintWriter(sock.getOutputStream()); 
        String request = ""; 
        // and write your code 
       } 
      } 
     }); 
     t.start(); 
    } 
} 
+0

壞的做法,要創建一個新的'Scanner'和'PrintWriter'每個循環中,兩個聲明應該在循環之外。 – BackSlash

+0

是的。這是正確的。我無意中複製並粘貼user2565623代碼中的這幾行代碼! :( – Vahid

+0

它仍然沒有工作,有多個客戶端可以在同一時間在一臺服務器上連接..但是當第一個客戶端退出連接時,另一個客戶端將被連接。這就像先到先得服務方法..任何建議請:) – InformationTechnology