2015-03-13 59 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