Android client only connecting once to server with LipeRMI - java

I have an Android client connecting to a Java server with LipeRMI (http://lipermi.sourceforge.net/).
To test this communication I have a button in my interface that when clicked sends a String "Test". It gets to the server and the server returns the String. It works fine, the problem is that it only works once. The server only accepts one time.
My Server code is the following:
public class TestServer implements TestService {
public TestServer() {
try {
CallHandler callHandler = new CallHandler();
callHandler.registerGlobal(TestService.class, this);
Server server = new Server();
server.bind(7777, callHandler);
server.addServerListener(new IServerListener() {
#Override
public void clientDisconnected(Socket socket) {
System.out.println("Client Disconnected: " + socket.getInetAddress());
}
#Override
public void clientConnected(Socket socket) {
System.out.println("Client Connected: " + socket.getInetAddress());
}
});
System.out.println("Server Listening");
} catch (LipeRMIException | IOException e) {
e.printStackTrace();
}
}
#Override
public String getResponse(String data) {
System.out.println("getResponse called");
System.out.println("The information received was: " + data);
return "Your data: " + data;
}
And in the Android client, in my MainActivity I have the following:
public class MainActivity extends Activity {
private String serverIP = "192.168.3.8";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnGet = (Button) findViewById(R.id.send);
btnGet.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
new Conn().execute();
}
});
}
class Conn extends AsyncTask<Void, Void, MainActivity> {
#Override
protected MainActivity doInBackground(Void... params) {
Looper.prepare();
try {
CallHandler callHandler = new CallHandler();
Client client = new Client(serverIP, 7777, callHandler);
TestService testService = (TestService) client.getGlobal(TestService.class);
String msg = testService.getResponse("Test");
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
client.close();
} catch (IOException e) {
e.printStackTrace();
}
Looper.loop();
return null;
}
}
They have the TestService interface in common so that I can use the methods from the server.
How can I change the server so that it can accept any number of times a call from the Android Client?

I had the same issue and I deleted the Looper.prepare() and Looper.loop() calls in the doInBackground method from AsyncTask. It solved the problem in my case.

Related

Create A client that can receive and send messages at the same time.In Java

I am trying to do A chat between clients(android) to a server with a socket connection. I want my client to be able to send messages to the server and at the same time to listen to messages that the server is sending back. I was able to do a thread that will do the connection and opens a thread that sends a message whenever the client presses a button but I don't know how to add a thread that will listen to server response.
here is my client code
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
TextView tv1;
Button btnSend;
EditText etMessage;
String message_data;
PrintWriter output;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv1 = (TextView) findViewById(R.id.tv);
etMessage = (EditText) findViewById(R.id.et_message);
btnSend = (Button) findViewById(R.id.button_send);
doConnection("Idan", "uid2");
}
#Override
public void onClick(View v) {
if (v== btnSend)
{
message_data = etMessage.getText().toString();
new Thread(new ThreadSend(message_data)).start();
}
}
public class ThreadSend implements Runnable{
private String messageTOSend;
ThreadSend(String message){
this.messageTOSend = message;
}
#Override
public void run() {
output.write(messageTOSend);
output.flush();
}
}
Thread thread = new Thread(){
#Override
public void run() {
super.run();
try {
Socket s = new Socket("10.0.0.5", 7979);
output = new PrintWriter(s.getOutputStream());
String connection_data = "Idan//uid1";
output.write(connection_data);
output.flush();
output.write("Hello");
output.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
};
private void doConnection(String userUid, String destinationUid) {
thread.start();
btnSend.setOnClickListener(this);
}
}
can someone help me or give me any advice where I can find information about it

After establishing TCP connection with server, why can't I see message sent from server?

I have made an app that should connect to a sensor via WiFi Direct, then connect to port 5001 on the sensor to get the sensor data.
I have used "Simple Socket Tester" to start a server on another phone to see if my app succeeded in connecting to port 5001 on that server. When connected, I can send messages to the server, which is displayed on the other phone. But when I send messages to the client from the other phone, I am not receiving the message in my app.
Why is that? Am I missing something inside my code?
public class TCPClient {
public static final String SERVER_IP = "192.168.1.52"; //your computer IP address
public static final int SERVER_PORT = 5001;
// message to send to the server
private String mServerMessage;
// sends message received notifications
private OnMessageReceived mMessageListener = null;
// while this is true, the server will continue running
private boolean mRun = false;
// used to send messages
private PrintWriter mBufferOut;
// used to read messages from the server
private BufferedReader mBufferIn;
/**
* Constructor of the class. OnMessagedReceived listens for the messages received from server
*/
public TCPClient(OnMessageReceived listener) {
mMessageListener = listener;
}
/**
* Sends the message entered by client to the server
*
* #param message text entered by client
*/
public void sendMessage(String message) {
if (mBufferOut != null && !mBufferOut.checkError()) {
mBufferOut.println(message);
mBufferOut.flush();
}
}
/**
* Close the connection and release the members
*/
public void stopClient() {
// send mesage that we are closing the connection
/*sendMessage(Constants.CLOSED_CONNECTION+"Kazy");*/
mRun = false;
if (mBufferOut != null) {
mBufferOut.flush();
mBufferOut.close();
}
mMessageListener = null;
mBufferIn = null;
mBufferOut = null;
mServerMessage = null;
}
public void run() {
mRun = true;
try {
//here you must put your computer's IP address.
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
Log.e("TCP Client", "C: Connecting...");
//create a socket to make the connection with the server
Socket socket = new Socket(serverAddr, SERVER_PORT);
try {
//sends the message to the server
mBufferOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
//receives the message which the server sends back
mBufferIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// send login name
sendMessage("hi");
//in this while the client listens for the messages sent by the server
while (mRun) {
mServerMessage = mBufferIn.readLine();
if (mServerMessage != null && mMessageListener != null) {
//call the method messageReceived from MyActivity class
mMessageListener.messageReceived(mServerMessage);
}
}
Log.e("RESPONSE FROM SERVER", "S: Received Message: '" + mServerMessage + "'");
} catch (Exception e) {
Log.e("TCP", "S: Error", e);
} finally {
//the socket must be closed. It is not possible to reconnect to this socket
// after it is closed, which means a new socket instance has to be created.
socket.close();
}
} catch (Exception e) {
Log.e("TCP", "C: Error", e);
}
}
//Declare the interface. The method messageReceived(String message) will must be implemented in the MyActivity
//class at on asynckTask doInBackground
public interface OnMessageReceived {
public void messageReceived(String message);
}
}
The class where my ConnectTask class is.
public class DeviceDetailFragment extends Fragment implements ConnectionInfoListener {
protected static final int CHOOSE_FILE_RESULT_CODE = 20;
private View mContentView = null;
private WifiP2pDevice device;
private WifiP2pInfo info;
ProgressDialog progressDialog = null;
TCPClient mTCPClient;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mContentView = inflater.inflate(R.layout.device_detail, null);
mContentView.findViewById(R.id.btn_connect).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
config.wps.setup = WpsInfo.PBC;
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
progressDialog = ProgressDialog.show(getActivity(), "Press back to cancel",
"Connecting to :" + device.deviceAddress, true, true
// new DialogInterface.OnCancelListener() {
//
// #Override
// public void onCancel(DialogInterface dialog) {
// ((DeviceActionListener)
getActivity()).cancelDisconnect();
// }
// }
);
((DeviceListFragment.DeviceActionListener) getActivity()).connect(config);
}
});
mContentView.findViewById(R.id.btn_disconnect).setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
((DeviceListFragment.DeviceActionListener) getActivity()).disconnect();
}
});
/*
mContentView.findViewById(R.id.btn_start_client).setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
// Allow user to pick an image from Gallery or other
// registered apps
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, CHOOSE_FILE_RESULT_CODE);
}
});
*/
return mContentView;
}
#Override
public void onConnectionInfoAvailable(final WifiP2pInfo info) {
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
this.info = info;
this.getView().setVisibility(View.VISIBLE);
// The owner IP is now known.
TextView view = (TextView) mContentView.findViewById(R.id.group_owner);
view.setText(getResources().getString(R.string.group_owner_text)
+ ((info.isGroupOwner == true) ? getResources().getString(R.string.yes)
: getResources().getString(R.string.no)));
// InetAddress from WifiP2pInfo struct.
view = (TextView) mContentView.findViewById(R.id.device_info);
view.setText("Group Owner IP - " + info.groupOwnerAddress.getHostAddress());
if(info.groupFormed) {
new ConnectTask().execute("");
if (mTCPClient != null) {
mTCPClient.sendMessage("testing");
}
//sends the message to the server
}
// After the group negotiation, we assign the group owner as the file
// server. The file server is single threaded, single connection server
// socket.
/*
if (info.groupFormed && info.isGroupOwner) {
new FileServerAsyncTask(getActivity(), mContentView.findViewById(R.id.status_text))
.execute();
}
*/
// hide the connect button
mContentView.findViewById(R.id.btn_connect).setVisibility(View.GONE);
}
/**
* Updates the UI with device data
*
* #param device the device to be displayed
*/
public void showDetails(WifiP2pDevice device) {
this.device = device;
this.getView().setVisibility(View.VISIBLE);
TextView view = (TextView) mContentView.findViewById(R.id.device_address);
view.setText(device.deviceAddress);
view = (TextView) mContentView.findViewById(R.id.device_info);
view.setText(device.toString());
}
/**
* Clears the UI fields after a disconnect or direct mode disable operation.
*/
public void resetViews() {
mContentView.findViewById(R.id.btn_connect).setVisibility(View.VISIBLE);
TextView view = (TextView) mContentView.findViewById(R.id.device_address);
view.setText(R.string.empty);
view = (TextView) mContentView.findViewById(R.id.device_info);
view.setText(R.string.empty);
view = (TextView) mContentView.findViewById(R.id.group_owner);
view.setText(R.string.empty);
/*
view = (TextView) mContentView.findViewById(R.id.status_text);
view.setText(R.string.empty);
this.getView().setVisibility(View.GONE);
*/
}
public class ConnectTask extends AsyncTask<String, String, TCPClient> {
#Override
protected TCPClient doInBackground(String... message) {
//we create a TCPClient object
mTCPClient = new TCPClient(new TCPClient.OnMessageReceived() {
#Override
//here the messageReceived method is implemented
public void messageReceived(String message) {
//this method calls the onProgressUpdate
publishProgress(message);
}
});
mTCPClient.run();
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
//response received from server
Log.d("test", "response " + values[0]);
//process server response here....
}
}
}

Android app using LipeRMI is connecting to server but not calling the method

I have an android app and a server, both using lipeRMI.
My android app successfully connects to the server. But the method it's supposed to call, is not being called.
Server Code:
public interface TestService {
public String getResponse(String data);
}
public class TestServer implements TestService {
public TestServer() {
try {
CallHandler callHandler = new CallHandler();
callHandler.registerGlobal(TestService.class, this);
Server server = new Server();
server.bind(7777, callHandler);
server.addServerListener(new IServerListener() {
#Override
public void clientDisconnected(Socket socket) {
System.out.println("Client Disconnected: " + socket.getInetAddress());
}
#Override
public void clientConnected(Socket socket) {
System.out.println("Client Connected: " + socket.getInetAddress());
}
});
System.out.println("Server Listening");
} catch (LipeRMIException | IOException e) {
e.printStackTrace();
}
}
#Override
public String getResponse(String data) {
System.out.println("getResponse called");
return "Your data: " + data;
}
public static void main(String[] args) {
TestServer testServer = new TestServer();
}
}
The android code:
interface TestService {
public String getResponse(String data);
}
public class MainActivity extends Activity {
private String serverIP = "192.168.1.7";
EditText et= null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnGet = (Button) findViewById(R.id.button1);
et= (EditText)findViewById(R.id.editText2);
btnGet.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
new Conn().execute();
}
});
}
class Conn extends AsyncTask<Void, Void, MainActivity> {
#Override
protected MainActivity doInBackground(Void... params) {
Looper.prepare();
try {
Toast.makeText(MainActivity.this, "Inside conn my nigga", Toast.LENGTH_SHORT).show();
CallHandler callHandler = new CallHandler();
Client client = new Client(serverIP, 7777, callHandler);
TestService testService = (TestService) client.getGlobal(TestService.class);
String msg = testService.getResponse("qwe");
//Toast.makeText(MainActivity.this, testService.getResponse("abc"), Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
client.close();
} catch (IOException e) {
e.printStackTrace();
}
Looper.loop();
return null;
}
}
}
I tried using the above code also using a simple Runnable thread instead of AsyncTask(I was paranoid AsyncTask'd be causing the problem) but it went in vain.
The server gives this output:
Server Listening
Client Connected: /192.168.1.5
Client Disconnected: /192.168.1.5
No matter how many times I click the Button1 of my android app.
Any help will be really appreciated. :)
Thank you for your time!
I had this situation when packages were different. You should make sure that TestService packages are same at Android application and server.
If you use your own class in TestService interface, it should have same packages too and should implement Serializable.

How to access the activity object in Android

MainActivity.java
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Client client = new Client();
try {
client.connect("192.168.1.10",5555);
} catch (IOException e) {
e.printStackTrace();
}
}
public void displayServerAnswer(String answer){
TextView textView = (TextView)findViewById(R.id.mainTextView);
textView.setText(answer);
}
...
Client.java
import java.net.Socket;
import java.io.PrintWriter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Observable;
public class Client extends Observable implements Runnable {
private Socket socket;
private BufferedReader br;
private PrintWriter pw;
private boolean connected;
private int port=5555; //default port
private String hostName="localhost";//default host name
public Client() {
connected = false;
}
public void connect(String hostName, int port) throws IOException {
if(!connected)
{
this.hostName = hostName;
this.port = port;
socket = new Socket(hostName,port);
//get I/O from socket
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
pw = new PrintWriter(socket.getOutputStream(),true);
connected = true;
//initiate reading from server...
Thread t = new Thread(this);
t.start(); //will call run method of this class
}
}
public void sendMessage(String msg) throws IOException
{
if(connected) {
pw.println(msg);
} else throw new IOException("Not connected to server");
}
public void run() {
String msg = ""; //holds the msg recieved from server
try {
while(connected && (msg = br.readLine())!= null)
{
//In Here I want to call MainActivity.displayServerAnswer()
//notify observers//
this.setChanged();
//notify+send out recieved msg to Observers
this.notifyObservers(msg);
}
}
catch(IOException ioe) { }
finally { connected = false; }
}
...
}
In the place I specified, I want to be able to display the server answer.
How can I get access to MainActivity instance that created client object, in order to call its method?
#hopia answer is pretty good. you also can implement the Listener Design pattern
public class Client extends Observable implements Runnable {
public interface ClientListener {
public void onAction();
}
private ClientListener mListener;
public Client(ClientListener listener) {
mListener = listener;
}
public class MainActivity extends ActionBarActivity implements ClientListener {
#Override
public void onAction(){
....do whatever you need
}
...
}
You can pass an acvtivity reference to your client in either a constructor or a set accessor method.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Client client = new Client(this);
try {
client.connect("192.168.1.10",5555);
} catch (IOException e) {
e.printStackTrace();
}
}
And in your java object:
MainActivity activity;
public Client(MainActivity activity) {
connected = false;
this.activity = activity;
}
...
public void run() {
String msg = ""; //holds the msg recieved from server
try {
while(connected && (msg = br.readLine())!= null)
{
//In Here I want to call MainActivity.displayServerAnswer()
activity.displayServerAnswer();
//notify observers//
this.setChanged();
//notify+send out recieved msg to Observers
this.notifyObservers(msg);
}
}
catch(IOException ioe) { }
finally { connected = false; }
}
How about passing the activity instance as an argument to the Client's constructor?
// MainActivity
Client client = new Client(this);
// Client
public Client(Activity activity) {
this.activity = activity;
connected = false;
}

Telnet late server reply

I have very strange problem with telnet communication. When I send a message to server, server will reply every time after next message. Server reply looks like this:
// bad IP transmitters adress message
If I send "first message" server will not reply. After I send "second message" server will reply to the first message. Every time reply from server is one message late.
My communication looks like this:
If I use Telnet application from Google Play Store it works perfect and communication looks like this:
C: first message
S: [// bad IP transmitters adress message 'first message']
C: second message
S: [// bad IP transmitters adress message 'second message']
C: third message
S: [// bad IP transmitters adress message 'third message']
Is there some way how fix it? Thank you so much!
Code:
TCPclass
public class TCPclass {
private boolean mRun = false;
String messageFromServer;
private OnMessageReceived mMessageListener = null;
PrintWriter out;
BufferedReader in;
public TCPclass(OnMessageReceived listener) {
mMessageListener = listener;
}
public void stopClient() {
mRun = false;
}
public void sendMessage(String message) {
if (out != null && !out.checkError()) {
message = message + '\r' + '\n';
out.print(message);
out.flush();
Log.i("Terminal", "Message sent.");
}
}
public void start(String hostname, int port) {
mRun = true;
try {
InetAddress serverAddr = InetAddress.getByName(hostname);
Socket socket = new Socket(serverAddr, port);
try {
out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
// receive the message which the server sends back
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
while (mRun) {
do
{
String messageFromServer = in.readLine();
if (messageFromServer != null && mMessageListener != null) {
mMessageListener.messageReceived(messageFromServer); //append message to Text View
}
messageFromServer = null;
} while (in.ready());
}
} catch (Exception e) {
Log.e("Terminal", "S: Error ", e);
} finally {
socket.close();
}
} catch (Exception e) {
Log.e("Terminal", "Establish connection error " + hostname + " "
+ port);
}
}
public interface OnMessageReceived {
public void messageReceived(String message);
}
}
MainActivity class:
public class MainActivity extends Activity {
private TCPclass mTcpClass;
public String hostname = "127.0.0.1";
public int port = 7011;
TextView serverMessage;
private connectTask mTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText IPaddress = (EditText) findViewById(R.id.eAddress);
final EditText ePort = (EditText) findViewById(R.id.ePort);
final EditText eMessage = (EditText) findViewById(R.id.eMessage);
serverMessage = (TextView) findViewById(R.id.tOutput);
Button okButton = (Button) findViewById(R.id.bOK); //Connect button
okButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) { // connect
// TODO Auto-generated method stub
hostname = IPaddress.getText().toString();
String strPort = ePort.getText().toString();
try {
port = Integer.parseInt(strPort);
} catch (NumberFormatException e) {
Log.e(strPort, "Error port");
}
mTask = new connectTask();
mTask.execute("");
}
});
Button sendButton = (Button) findViewById(R.id.bSend);
sendButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String message = eMessage.getText().toString();
serverMessage.append("C: " + message + "\n");
Log.i("Terminal", "Sending message " + message);
if (mTcpClass != null) {
mTcpClass.sendMessage(message);
}
eMessage.setText("");
}
});
}
public class connectTask extends AsyncTask<String, String, TCPclass> {
#Override
protected TCPclass doInBackground(String... message) {
Log.i("Terminal", "doInBackground.");
mTcpClass = new TCPclass(new TCPclass.OnMessageReceived() {
#Override
// here the messageReceived method is implemented
public void messageReceived(String message) {
// this method calls the onProgressUpdate
publishProgress(message);
}
});
mTcpClass.start(hostname, port);
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
serverMessage.append("S: " + Arrays.toString(values) + "\n");
}
}
It seems to me that the server is probably sending a blank or extra line somewhere that you haven't accounted for. I'm the world's last and least fan of calling available() or ready() but maybe this is a case for it:
do
{
String response = in.readLine();
// ...
} while (in.ready());
... at least for debugging purposes, until you sort out exactly what the response is to each line you send. Note that using a while loop here would be definitely incorrect.

Categories