Search code examples
javaserversocketsclienttcp

Return message to Android client from java Server via tcp sockets


I am trying to make a very simple client/server connection. I have Android app as a client and trying to

1) pass message to Java program on PC and then

2) return a message back to the android client.

First part is working fine. The problem is in returning the message from server to client.

Server code (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();
            }

        }

    }
}

Client main activity (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(); 
            }
         });
    }
}

Separate AsyncTask class for connection:

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();
    }
}

The java program executes ok and the Android app runs without any problems but the end result is not as desired.

If I remove the second socket = new Socket(IP, PORT); // second connection to server , then server is receiving messages fine. In the java console I get printed whatever I put in the app and send. But the second Toast is empty (the message from the server is not passed). And I get SocketException (closed) in the LogCat:

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)

If I leave socket = new Socket(IP, PORT); // second connection to server line of code in, there are no error messages, but the message is passed only once to the server. 2nd, 3rd, end so forth don't go through (nothing displaying in the console). Though if I leave the console running and shut down the app, another null comes through.

In any case, the second Toast (on the client side) is either empty (the message from the server is not passed) or not displayed at all (message = bufferedReader.readLine(); blocks further execution). For instance, If I comment out the line message = bufferedReader.readLine(); , then I get "after isr" in the second Toast. Or, in the case when the second socket = new Socket(IP, PORT); // second connection is present the second Toast does not display at all.

What am I missing. How do I send a message from server back to the client?


Solution

  • The instructions of client and server must be symmetric.

    If the client writes, the server must read and viceversa

    If the client opens an inputStream, the server must open an outputStream.

    Now in the first connection you open only the outputStream but in the server you have both of them.

    Also you open two connections (client) that are handled as one in the server, so the first printing operations work fine because there are reading operations on server, but the others can't work because you create another connection that the server can't handle because:

    1)the server is not multithread

    2)the server have to work on the first connection