使用Service或IntentService在Android客户端/服务器Socket通信

4
到目前为止,我已经成功在一台安卓设备上启动了一个服务器(使用wifi热点/共享网络),并让另一台安卓设备作为客户端连接到该服务器,并发送消息。服务器再回复这些消息。我意识到需要一种方法来使服务器保持对客户端的监听,即使聊天应用程序没有运行。客户端应该能够发送消息,而服务器应该接收到这些消息。我应该使用Service还是IntentService来实现这一点?我无法从AsyncTask和Service中继承...如何实现这一点?一些示例代码会很棒。

以下是我的服务器外观:

public class Server extends AsyncTask<Integer, Void, Socket> {

    private ServerSocket serverSocket;
    private TextView textView;
    private String incomingMsg;
    private String outgoingMsg;

    public Server(TextView textView) {
        this.textView = textView;
    }

    public void closeServer() {
        try {
            serverSocket.close();
        } catch (IOException e) {
            Log.d("Server", "Closung the server caused a problem");
            e.printStackTrace();
        }       
    }


    @Override
    protected Socket doInBackground(Integer... params) {

        try {
            serverSocket = new ServerSocket(params[0]);       

            //accept connections
            Socket socket = serverSocket.accept();

            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            incomingMsg = in.readLine() + System.getProperty("line.separator");

            //send a message
            outgoingMsg = "You are connected to the Server" + System.getProperty("line.separator");
            out.write(outgoingMsg);
            out.flush();

            return socket;


        } catch (InterruptedIOException e) {
            //if timeout occurs
            e.printStackTrace();

        } catch (IOException e) {
            e.printStackTrace();

        } 
//      finally {
//          if (serverSocket != null) {
//              try {
//                  serverSocket.close();
//              } catch (IOException e) {
//                  e.printStackTrace();
//              }
//          }
//      }

        return null;
    }


    protected void onPostExecute(Socket socket) {

        if(socket != null) {
            try {

                Log.i("Server", "Server received: " + incomingMsg);
                textView.setText("Server received: " + incomingMsg + "\n");

                textView.append("Server sent: " + outgoingMsg + "\n");
                Log.i("Server", "Server sent: " + outgoingMsg);

                socket.close();

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        } else {
            Log.d("Server", "Can't communicate with the client!");
        }
    }
}

这是我的客户端:

public class Client extends AsyncTask<Integer, Void, Socket> {

    private WifiManager wifi;
    private Context context;
    private String outMsg;
    private String inMsg;

    public Client(Context context, WifiManager wifiManager) {
        this.context = context;
        this.wifi = wifiManager;
    }

    @Override
    protected Socket doInBackground(Integer... params) {

        try {

            String gateway = intToIp(wifi.getDhcpInfo().gateway);
            Socket socket = new Socket(gateway, params[0]);

            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

            String ipAdress = intToIp(wifi.getConnectionInfo().getIpAddress());

            outMsg = ", Client " + ipAdress +" is connecting!" + System.getProperty("line.separator"); 
            out.write(outMsg);
            out.flush();

            //accept server response
            inMsg = in.readLine() + System.getProperty("line.separator");

            return socket;

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

        return null; 
    }


    public String intToIp(int addr) {
        return  ((addr & 0xFF) + "." + 
                ((addr >>>= 8) & 0xFF) + "." + 
                ((addr >>>= 8) & 0xFF) + "." + 
                ((addr >>>= 8) & 0xFF));
    }


    protected void onPostExecute(Socket socket) {

        if(socket != null) {

            Log.i("Client", "Client sent: " + outMsg);
            Toast.makeText(context, "\nClient sent: " + outMsg + "\n", Toast.LENGTH_LONG).show();

            Log.i("Client", "Client received: " + inMsg);
            Toast.makeText(context, "Client received: " + inMsg + "\n", Toast.LENGTH_LONG).show();

        } else {
            Log.d("Client", "Can't connect to server!");
            Toast.makeText(context, "Can't connect to server!", Toast.LENGTH_LONG).show();
        }           
    }
}

如何将服务器转化为服务?客户端也应该成为服务吗?

只需让服务器保持运行状态。 - Viswanath Lekshmanan
好的,那么使用Service或IntentService怎么样?在Service的情况下如何与AsyncTask结合使用? - user574080
1个回答

3
使用服务,但忘记AsyncTask。让您的服务启动通用线程(https://developer.android.com/reference/java/lang/Thread.html)并设置套接字+侦听器。此服务甚至可以处理消息发送(通过下面链接中涵盖的许多选项之一)。请勿忘记在Service的onDestroy()中正确清理线程。
还要注意,如果您希望应用程序继续从其他客户端接收消息,则需要确保将服务强制置于前台(请参见http://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification)。但是,这并非万无一失,您的服务仍然可能会被杀死。
这就是为什么人们倾向于使用托管在某些专用框中的服务器,而不是每个个体设备...

在这里使用一个带有newFixedThreadPool的ExecutorService(http://developer.android.com/reference/java/util/concurrent/Executors.html#newFixedThreadPool)是否明智? - IgorGanapolsky
当然,如果您正在运行多个线程,最好使用ExecutorService来管理它们。使用newFixedThreadPool可能意味着您正在限制可以连接的用户数量,这取决于您如何构建服务器(使用什么协议等)。 - kwazi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接