通过tcp套接字从java Server返回到Android客户端的消息

时间:2015-01-31 01:46:38

标签: java server sockets client tcp

我是Android的初学者,具有中级Java编程技能。我也只是学习套接字通信。我正在尝试建立一个非常简单的客户端/服务器连接。我有Android应用程序作为客户端并尝试

1)将消息传递给PC上的Java程序然后

2)将消息返回给Android客户端。

第一部分工作正常。问题在于将消息从服​​务器返回到客户端。

服务器代码(Java):

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


public class Main {

    private final static Integer IN_PORT = 4444; 

    private static ServerSocket serverSocket = null;
    private static Socket sktIn;
    private static InputStreamReader inputStreamReader;
    private static BufferedReader bufferedReader;
    private static String message;

    private static PrintWriter printWriter;

    public static void main(String[] args) {

        try {
            serverSocket = new ServerSocket(IN_PORT);  //Server socket
            System.out.println("Server started. Listening to the port " + IN_PORT);        
        } catch (IOException e) {
            System.out.println("Could not listen on port: " + IN_PORT);
        }


        while (true) {
         try {
          sktIn = serverSocket.accept();   //accept the client connection
                inputStreamReader = new InputStreamReader(sktIn.getInputStream());
                bufferedReader = new BufferedReader(inputStreamReader); //get the client message
                message = bufferedReader.readLine();

                printWriter = new PrintWriter(sktIn.getOutputStream(), true);
                printWriter.write("Returned back \n");  //write the message to output stream
                printWriter.flush();
                printWriter.close();             
                inputStreamReader.close();               
                sktIn.close();

                System.out.println(message);                               

            } catch (IOException ex) {
                System.out.println("Problem in message reading/sending.");
                ex.printStackTrace();
            }

        }

    }
}

客户主要活动(Android):

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class SimpleClientActivity extends Activity {

    private final Integer OUT_PORT = 4444;
    private final String S_IP = "192.168.1.104"; 

    private EditText textField;
    private Button button;
    private String message;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);    

        textField = (EditText) findViewById(R.id.editText1); //reference to the text field
        button = (Button) findViewById(R.id.button1);   //reference to the send button

        //Button press event listener
        button.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {

                message = textField.getText().toString(); //get the text message on the text field
                textField.setText("");      //Reset the text field to blank

                new ConnectClient(message, S_IP, OUT_PORT, getApplicationContext()).execute(); 
            }
         });
    }
}

用于连接的单独AsyncTask类:

import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class ConnectClient extends AsyncTask<String, Void, String> {

    private Socket socket;
    private PrintWriter printWriter;

    private String param;   
    private Context context;
    private Integer PORT;
    private String IP;

    private static InputStreamReader inputStreamReader;
    private static BufferedReader bufferedReader;
    private static String message;


 public ConnectClient(String par, String ip, Integer prt, Context ctx){
  super();
     this.context = ctx;
     this.param = par;
     this.PORT = prt;
     this.IP = ip;
 }

 @Override
    public void onPreExecute() {
        Toast.makeText(context, "start " + param, Toast.LENGTH_SHORT)
           .show();
    }

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

        try {
                socket = new Socket(IP, PORT);  //connect to server

                printWriter = new PrintWriter(socket.getOutputStream(), true);
                printWriter.write(param);  //write the message to output stream

                printWriter.flush();
                printWriter.close();

                socket = new Socket(IP, PORT); // second connection to server     
                inputStreamReader = new InputStreamReader(socket.getInputStream());
                message = "after isr";
                bufferedReader = new BufferedReader(inputStreamReader); //get the client message
                message = bufferedReader.readLine();
                inputStreamReader.close();          
                socket.close();   //closing the connection

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

        return message;
    }

    @Override
    protected void onPostExecute(String result) {
        Toast.makeText(context, result, Toast.LENGTH_SHORT).show()   
    }

    @Override
    protected void onProgressUpdate(Void... values) {
        Toast.makeText(context, "In progress", Toast.LENGTH_SHORT).show();
    }
}

java程序执行正常,Android应用程序运行没有任何问题,但最终结果不是所希望的。

如果删除第二个socket = new Socket(IP, PORT); // second connection to server,则服务器正在接收消息。在java控制台中,无论我放入应用程序并发送,我都会打印出来。但第二个Toast为空(来自服务器的消息未通过)。我在LogCat中得到SocketException(已关闭):

01-29 06:38:36.039: W/System.err(11547): java.net.SocketException: Socket is closed
01-29 06:38:36.059: W/System.err(11547):  at java.net.PlainSocketImpl.checkNotClosed(PlainSocketImpl.java:134)
01-29 06:38:36.059: W/System.err(11547):  at java.net.PlainSocketImpl.getInputStream(PlainSocketImpl.java:216)
01-29 06:38:36.059: W/System.err(11547):  at java.net.Socket.getInputStream(Socket.java:343)
01-29 06:38:36.059: W/System.err(11547):  at com.example.simpleclient.ConnectClient.doInBackground(ConnectClient.java:63)
01-29 06:38:36.059: W/System.err(11547):  at com.example.simpleclient.ConnectClient.doInBackground(ConnectClient.java:1)
01-29 06:38:36.059: W/System.err(11547):  at android.os.AsyncTask$2.call(AsyncTask.java:287)
01-29 06:38:36.059: W/System.err(11547):  at java.util.concurrent.FutureTask.run(FutureTask.java:234)
01-29 06:38:36.059: W/System.err(11547):  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
01-29 06:38:36.059: W/System.err(11547):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
01-29 06:38:36.059: W/System.err(11547):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
01-29 06:38:36.059: W/System.err(11547):  at java.lang.Thread.run(Thread.java:841)

如果我留下socket = new Socket(IP, PORT); // second connection to server代码行,则没有错误消息,但消息只传递给服务器一次。第2,第3,结束等不要通过(控制台中没有显示)。虽然如果我让控制台运行并关闭应用程序,另一个null就会通过。

在任何情况下,第二个Toast(在客户端)都是空的(来自服务器的消息未通过)或者根本没有显示(message = bufferedReader.readLine();阻止进一步执行)。例如,如果我注释掉行message = bufferedReader.readLine();,那么我会在第二个Toast中获得“after isr”。或者,在第二个socket = new Socket(IP, PORT); // second connection出现的情况下,第二个Toast根本不显示。

我错过了什么。如何从服务器向客户端发送消息?

1 个答案:

答案 0 :(得分:1)

客户端和服务器的指令必须是对称的。

如果客户端写入,则服务器必须读取并反之亦然

如果客户端打开inputStream,则服务器必须打开outputStream。

现在在第一个连接中,你只打开outputStream,但在服务器中你同时打开它们。

此外,您打开两个在服务器中作为一个连接处理的连接(客户端),因此第一个打印操作正常,因为服务器上有读取操作,但其他连接无法工作,因为您创建了另一个连接,服务器无法处理,因为:

1)服务器不是多线程的

2)服务器必须处理第一个连接