2012-07-24 46 views
0

自從兩天以來,我對此代碼感到痛苦。事實上,我正在開發一個具有服務器端和客戶端的應用程序。服務器每秒接收到來自客戶端的請求,通過聯繫數據庫來處理請求,然後將結果發送回客戶端。 我這樣做,如果客戶端在服務器之前啓動,它將繼續嘗試連接到給定端口和給定主機上的服務器。
1.這是服務器側:MultiClient/Server。處理通訊

try 
    { 
     Client client = new Client(jTable1,jLabel3); 
     Thread t = new Thread(client); 
     t.start(); 

    }catch(IOException e){} 

類Client.java

public class Client implements Runnable{ 

private int svrPort = 0; 
ServerSocket serverConnect = null; 
static Socket clientSocket = null; 
static ClientConnectThread t[] = new ClientConnectThread[1000]; 
JTable jtable; 
JLabel jlabel; 

public Client(JTable table, JLabel label) throws IOException { 

    this.svrPort = 9450; 
    this.jtable = table; 
    this.jlabel = label; 

} 

public void run(){ 
    try{ 
     serverConnect = new ServerSocket(this.svrPort); 

    }catch(IOException e){} 
    while(true){ 
     try{ 
      clientSocket = serverConnect.accept(); 
      for(int i=0; i<=1000; i++){ //I can accept up to 1000 clients 
     if(t[i]==null) 
     { 
      (t[i] = new ClientThread(client, t, jtable, jlabel)).start(); 
         System.out.println ("Etat12. Apres bloc try"); 
      break; 
     } 
    } 
     }catch(IOException e){} 
    } 
} 

}

類ClientThread.java

public ClientThread(Socket socket, ClientThread t[], JTable table, JLabel label){ 

    this._socket = socket; 
    this.jTable = table; 
    this.jlabel = label; 
    this.totalConnected = 0;  
    this.t = t; 
} 

public void run(){ 

    int index = 0; 
    try{ 
     this._output = new PrintWriter(this._socket.getOutputStream()); 
     this._input = new BufferedReader(new InputStreamReader(this._socket.getInputStream())); 

     while((clientMsg = this._input.readLine()) != null){ 
      if(clientMsg.equals ("@CONNECT")){ // If it is the first time the user is signig in, fill the table 

       jTable.setValueAt (this._socket.getInetAddress(), index, 0); 
       jTable.setValueAt (new Date(), index, 1); 
       jTable.setValueAt (new Date(), index, 2); 
       totalConnected++; 
       jlabel.setText (""); 
       jlabel.setText (totalConnected+""); 

      }else if(Integer.parseInt (clientMsg) == 1){ 
       int p = Integer.parseInt (clientMsg); 
       this._output = new PrintWriter(this._socket.getOutputStream(), true); 
       if (this.getData.connect()) 
       { 
        if(this.getData.getDataByType (1).size() == 0){ 
        } 
        _output.println (this.getData.getDataByPeriod (1)); 
       }else{System.out.println("You are not connected to the database server");} 

      }else if(Integer.parseInt (clientMsg) == 2){ 
       int p = Integer.parseInt (clientMsg); 
       this._output = new PrintWriter(this._socket.getOutputStream(), true); 
       if (this.getData.connect()) 
       { 
        if(this.getData.getDataByPeriod (2).size() == 0)System.out.println ("There is no data corresponding"); 
        this._output.println (this.getData.getDataByPeriod (2)); 
       }else{System.out.println("You are not connected to the database server");} 


      }else if(Integer.parseInt (clientMsg) == 3){ 
       int p = Integer.parseInt (clientMsg); 
       this._output = new PrintWriter(this._socket.getOutputStream(), true); 
       if (this.getData.connect()) 
       { 
        if(this.getData.getDataByType (3).size() == 0)System.out.println ("There is no data corresponding"); 
        this._output.println (this.getData.getDataByType (30)); 
       }else{System.out.println("You are not connected to the database server");} 


      }else if(Integer.parseInt (clientMsg) == 4){ 
       int p = Integer.parseInt (clientMsg); 
       this._output = new PrintWriter(this._socket.getOutputStream(), true); 
       if (this.getData.connect()) 
       { 
        if(this.getData.getDataByType (4).size() == 0)System.out.println ("There is no data corresponding"); 
        this._output.println (this.getData.getDataByType (60)); 
       }else{System.out.println("You are not connected to the database server");} 


      }else{ 

      } 
     } 
     this._input.close(); 
     this._output.close(); 
    }catch(IOException e){} 

} 

這些是兩個類使我的服務器運行。 Client.java類啓動並等待接受連接。當客戶端連接clientThread的一個實例被創建並關聯到客戶端時。 直到這裏,每件事似乎都運作良好。

客戶端

public class ServerConnect implements Runnable{ 

public static Socket clientSocket = null; 
public static PrintWriter out = null; 
public static BufferedReader in = null; 
public static int port=9450; 
public static String host = "127.0.0.1"; 
public static JLabel myLabel; 
public static JButton button; 
public static ResourceMap resourceMap; 
private static String serverMsg = ""; 

public ServerConnect(JLabel jLabel, JButton b) 
{ 
    jLabel.setText ("Trying to contact the server"); 
    myLabel = jLabel; 
    button = b; 
    port = Integer.parseInt("9450"); 
    host = "127.0.0.1"; 

     try{ 
      clientSocket = new Socket(host, port); 
      }catch(IOException e){e.printStackTrace();} 

} 

public void run() 
{ 
    while(true){ 
     while(!this.connect()) 
     {myLabel.setText ("You are not connected to the server : "+host); 
     button.setEnabled (false); 
      try{ 
       clientSocket = new Socket(host, port); 
      }catch(IOException e){} 
     } 

     myLabel.setText ("You are connected to the server : "+host); 
     button.setEnabled (true); 
     try{ 
      out = new PrintWriter(clientSocket.getOutputStream(), true); 
      out.println("@CONNECT"); 

      in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
      while((serverMsg = in.readLine()) != null){ 
       System.out.println ("<=> :"+serverMsg); 
      } 
     } 
     catch(IOException e){e.printStackTrace();} 
    } 
} 
private boolean connect() 
{ 
    try{ 
     clientSocket = new Socket(host, port); 
     return true; 
    }catch(IOException e){} 
    return false; 
}} 

我的問題是,當雙方開始,客戶端發送@CONNECT的唯一的事情,服務器接收它,這裏所有停止。如果客戶端再次發送請求,則服務器不應答。
我希望有人向我展示如何設置此應用程序
- 服務器端。使用WHILE循環接受線程連接
- 客戶端。在另一個線程中,每次嘗試聯繫服務器以建立連接
- 在另一個線程中,客戶端向服務器發送請求
- 服務器是另一個線程從數據庫請求信息併發送回客戶端。

我非常感謝你的幫助

+0

您可以添加服務器代碼嗎?這裏的一切似乎都貼上了客戶端 – 2012-07-24 05:50:50

+0

好吧,'所有站在這裏' - 在哪裏?當服務器收到「@CONNECT」消息時,服務器是否將這些值設置在表中?它是否回到'input.readLine()'?它是否曾經在'if/then/else'階段開始?如果你已經完成了這個簡單的調試,你應該告訴我們。如果不是,爲什麼不呢?通過博客進行調試非常緩慢且效率低下 - 如果您做了一些操作,整個過程都更容易:) – 2012-07-24 05:56:25

+0

@AlexColeman服務器代碼已添加到頂部,因此它是標籤Client。它寫在客戶端的某個地方。客戶端代碼從那裏開始。 – DeathCoder 2012-07-24 06:46:39

回答

1

Ooohh喔其一個壞主意,把一切都在一個低水平插座使用PrintWriter等 我在過去幾個編碼和多線程錯誤。所以我的(當然有點慢,但易於使用)的解決方案是:灰熊。

的最大優點是:可以修改和擴展傳輸對象很容易,無需修改代碼運輸(低級別插座寫)

接口...

public interface I_ServiceCommons { 
     public static final String MEDIATYPE   = "text/xml"; 
     public static final String MEDIATYPE_ENCODING = I_ServiceCommons.MEDIATYPE + "; charset=utf-8"; 
     public static final String SERIVCENAME = "/FUNNY_SERVICE_V001"; 
    } 

服務器端代碼

@Path(I_ServiceCommons.SERIVCENAME) 
public class YourService { 

    @POST 
    @Produces(I_ServiceCommons.MEDIATYPE) 
    @Consumes(I_ServiceCommons.MEDIATYPE) 
    public ResultObject request(final RequestObject yourRequest) { 
     //process here your request in Server 
    } 
} 

你的客戶....

public class abstract YourAbstractClient{ 
     protected Logger       log    = Logger.getLogger(this.getClass()); 
     protected final String      serviceUrl; 
     private final WebResource     resource; 

     public YourAbstractClient(final String url) { 
      this.serviceUrl = url + getService(); 
      this.resource = Client.create().resource(this.serviceUrl); 
     } 

     public abstract String getService(); 

     protected <RES, REQ> RES post(final Class<RES> resultClazz, final REQ req) { 
      final Builder builder = this.resource.type(I_ServiceCommons.MEDIATYPE).accept(I_ServiceCommons.MEDIATYPE); 
      try { 
       final RES result = builder.post(resultClazz, req); 
       return result; 
      } catch (final Exception e) { 
       throw new RuntimeException("Error posting data to [" + this.serviceUrl + "]: " + e.getMessage(), e); 
      } 
     } 

    } 

您的服務客戶...

public class Service extends YourAbstractClient { 

    public Service(final String url) { 
     super(url); 
    } 

    public MyResult getResult(final MyRequest req) { 
     return super.post(MyResult.class, req); 
    } 

    @Override 
    public String getService() { 
     return I_ServiceCommons.SERIVCENAME; 
    } 
} 

你TransferObjects

@XmlRootElement 
public class MyRequest implements Serializable { 
    public void setRequestType(final int p_AequestType) { 
     this.requestType = p_AequestType; 
    } 

    public int getRequestType() { 
     return this.requestType; 
    } 
} 

而結束......

String url = "http://127.0.0.1"; 
GrizzlyServerFactory.create(url) //starts the server 
MyRequest res = new MyRequest(); 
MyResult result = new Service(url).getResult(req); // Corrected 
+0

我不明白這段代碼。你能解釋一下嗎? – DeathCoder 2012-07-24 07:41:55

+1

查看我的回答http://stackoverflow.com/a/11626713/1268954 – Mirko 2012-07-24 08:10:44

0

很安靜簡單 - 但在墊層技術是複雜的。 ;) 我以相反的順序解釋它(我的回答@https://stackoverflow.com/a/11625335/1268954)。

在主代碼中,您啓動了GrizzlyServerFactory.create(url)的Grizzlyserver,它在「127.0.0.1」上偵聽。

服務器啓動時,它會使用Annotation @Path ...搜索類並找到「YourService」。

因此,灰熊將在URL「http://127.0.0.1/FUNNY_SERVICE_V001」(參見I_ServiceCommons)上註冊ServiceClass「YourService」。

那麼..我們再次在主代碼。我們創建一個MyRequest對象並創建一個具體服務「Service」的實例。一個更好的名字應該是「ServiceClient」,因爲它的代碼在客戶端。通過URL(「http://127.0.0.1」)創建「服務」,並在YourAbstractClient中對所有客戶端的公共構造函數代碼進行操作,並創建服務URL「http://127.0.0.1/FUNNY_SERVICE_V001」。 YourAbstractClient內部將創建一個客戶端對象(用於連接/編碼處理等)。 當我們想要訪問服務器時,我們只需要將MyRequest對象放入「服務」的「getResult」方法中即可。 YourAbstractClient中的客戶端將MyRequest對象轉換爲XML Reresentation(注意@XMLRootElement Annotation,無參數構造函數以及set/get Methods),對服務器執行HTTP POST,從而重新創建MyRequest對象。

所以在服務器端再次... 因此,當一個客戶端連接到「http://127.0.0.1/FUNNY_SERVICE_V001」以正確的方式,服務器創建YourService(參構造函數需要)的實例,並讀取XML,創建transferobject MyRequest和把它放到方法public ResultObject request(final RequestObject yourRequest)中,因爲它用@POST註解(在客戶端中做了HTTP-POST)註解。你可以處理你的MyReqeust對象必須返回一個MyResult對象,它將被轉換爲xml,發送,由客戶端接收並重新創建爲MyResult對象。而已。