2015-03-13 62 views
0

我需要我的服務器來跟蹤它的每個客戶端連接。我被建議使用線程。所以我想要實現的是爲每個客戶端創建一個Thread,它應該運行直到客戶端連接存在。但是,發生的情況是,對於每個客戶端發送的消息,都會在doInBackground()函數中創建一個新的客戶端連接。因此,我沒有爲單個客戶端提供單個線程,而是爲發送給服務器的任何客戶端消息獲取一個線程。你能提出一種方法,我的服務器能夠區分不同客戶端發送的不同消息嗎?無法管理單個java服務器的多個客戶端(android設備)

Java服務器代碼:

package com.nss.academyassistserver; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.net.ServerSocket; 
import java.net.Socket; 

public class AcademyAssistServer { 
    public static ServerSocket serverSocket; 
    public static Socket clientSocket; 

    static final int PORT = 4444; 

    public static void main(String[] args) { 
     // TODO Auto-generated method stub 
     try { 
      serverSocket = new ServerSocket(PORT); // Server socket   
     } catch (IOException e) { 
      System.out.println("Could not listen on port: "+PORT+" \n"); 
     } 
     System.out.println("Server started. Listening to the port "+PORT); 

     while (true) { 
      try { 
       clientSocket = serverSocket.accept(); 
       System.out.println("New connection accepted."); // accept the client connection 
      } catch (IOException ex) { 
       System.out.println("Problem in message reading"); 
      } 
      //new thread for a client    
      new EchoThread(clientSocket).start(); 
     } 
    } 
} 

class EchoThread extends Thread { 

    InputStreamReader inputStreamReader; 
    BufferedReader bufferedReader; 
    String fromClient; 
    Socket clientSocket; 

    public EchoThread(Socket clientSocket) { 
     this.clientSocket = clientSocket; 
    } 

    public void run() { 
     try { 
      inputStreamReader = new InputStreamReader(clientSocket.getInputStream()); 
      bufferedReader = new BufferedReader(inputStreamReader); // get the client message 
     } catch (IOException e) { 
      return; 
     } 

     while (!Thread.currentThread().isInterrupted()) { 
      System.out.println("I am thread " + Thread.currentThread().getId()); 
      try { 
       fromClient = bufferedReader.readLine(); 
       if ((fromClient == null) || fromClient.equalsIgnoreCase("exit")) { 
        System.out.println("You're welcome, bye!"); 

        return; 
       } else { 
        System.out.println(fromClient); 
        Thread.currentThread().interrupt(); 
       } 
      } catch (IOException e) { 
       e.printStackTrace(); 
       return; 
      } 
     } 
     try { 
      clientSocket.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

客戶活動代碼:

package com.nss.academyassist; 

    import java.util.ArrayList; 
    import java.util.Arrays; 
    import java.util.Locale; 

    //import statements for client 
    import java.io.IOException; 
    import java.io.PrintWriter; 
    import java.net.Socket; 
    import java.net.UnknownHostException; 

    import android.app.Activity; 
    import android.content.Intent; 
    import android.os.Bundle; 
    import android.view.Menu; 
    import android.view.MenuItem; 
    import android.view.View; 
    import android.view.View.OnClickListener; 
    import android.view.Window; 
    import android.view.WindowManager; 
    import android.widget.Button; 
    import android.widget.EditText; 
    import android.widget.ImageButton; 
    import android.widget.Toast; 

    //import statements for client 
    import android.os.AsyncTask; 


    public class MainActivity extends Activity implements OnClickListener { 

     EditText question; 

     //Client sockets 
     private Socket client; 
     private PrintWriter printwriter; 
     private String toTag; 

     @Override 
     protected void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState);   
      setContentView(R.layout.activity_main); 

      question = (EditText)findViewById(R.id.editText1); 

      Button query = (Button)findViewById(R.id.button2); 
      query.setOnClickListener(this); 
     } 

     private class SendMessage extends AsyncTask<Void, Void, Void> { 

      @Override 
      protected Void doInBackground(Void... params) { 

       try { 
        client = new Socket("Server IP Address", 4444); 
        printwriter = new PrintWriter(client.getOutputStream(), true); 
        printwriter.write(toTag); // write the message to output stream 

        printwriter.flush(); 
        printwriter.close(); 
        client.close(); // closing the connection 

       } catch (UnknownHostException e) { 
        e.printStackTrace(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
       return null; 
      } 
     } 

     public void onClick(View v) 
     { 
      switch(v.getId()) 
      { 
       case R.id.button2: 

         toTag = question.getText().toString(); 
         // Output the result 
         Toast.makeText(getApplicationContext(), toTag, 
             Toast.LENGTH_LONG).show(); 

         //Invoke the execute method of AsynTask, which will run the doInBackground method of SendMessage Class 
         SendMessage sendMessageTask = new SendMessage(); 
         sendMessageTask.execute(); 

        break; 
      } 

     } 
} 

回答

1

您可以使用IP來告訴客戶。使用

clientSocket.getInetAddress().getHostAddress() 

您還可以讓客戶端在android代碼中不關閉。例如,您可以打開中的onCreateclose它在onDestroy中。

1

問題的原因是在您的客戶端代碼中。使用new Socket(..),您的客戶端每次向服務器發送標籤時都會創建一個新連接。因此,而不是,你可以創建一個重用的單個連接:

public class MainActivity extends Activity implements OnClickListener { 

    /* .. your other variables .. */ 

    private Socket client; 
    private PrintWriter printwriter; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     /* .. no change here .. */ 
    } 

    public void onStart() 
    { 
     if(this.client != null) 
     { 
      try { 
       client = new Socket("Server IP Address", 4444); 
       printwriter = new PrintWriter(client.getOutputStream(), true); 
      } catch (UnknownHostException e) { 
       e.printStackTrace(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    public void onClose() 
    { 
     this.printwriter.close(); 
     this.printwriter = null; 
     this.client.close(); 
     this.client = null; 
    } 

    private class SendMessage extends AsyncTask<Void, Void, Void> { 

     @Override 
     protected Void doInBackground(Void... params) { 
      try { 
       printwriter.write(toTag); // write the message to output stream 
       printwriter.write("\n"); // delimiter 
       printwriter.flush(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
      return null; 
     } 
    } 

    public void onClick(View v) 
    { 
     switch(v.getId()) 
     { 
      case R.id.button2: 

        toTag = question.getText().toString(); 
        // Output the result 
        Toast.makeText(getApplicationContext(), toTag, 
            Toast.LENGTH_LONG).show(); 

        //Invoke the execute method of AsynTask, which will run the doInBackground method of SendMessage Class 
        SendMessage sendMessageTask = new SendMessage(); 
        sendMessageTask.execute(); 

       break; 
     } 

    } 
} 

此外,你應該附加一些分隔符的標籤/信息,以使服務器能夠從不同的信息內容區分。

由於使用BufferedReader.readLine()其通過換行中的任何一個(「\ n」)的方式隔開線

,回車(「\ r」),或一個 回車由緊跟一個換行

爲了達到上述目的,我在上面的例子中添加了一行在標籤之後添加換行。

+0

是的,每次客戶端發送標籤到服務器時,使用新的Socket(..)都會創建一個新的連接。你的建議,給出了一個錯誤,因爲我們無法在android的主UI線程上進行任何網絡操作。這就是我在AsynTask中完成它的原因。 – 2015-03-13 09:18:56

+0

在這種情況下,我認爲您需要3個AsyncTasks:1用於連接onCreate(),1用於發送消息,1用於斷開onClose() – ultimate 2015-03-19 15:49:26

+0

這正是我以後所做的。謝謝。 :) – 2015-03-22 11:00:45