Android Studio Client-Server message struggle - android

I have a server app in android studio and a client app.
Although the client is able to connect to server I can't seem to pass a message through to the client. I am very new to the networking concept so a little help would be much appreciated.
My MainActivity Class:
public class MainActivity extends Activity {
Server server;
TextView infoip, msg;
TextView usersTitle;
EditText userInput;
Button sendButton;
String[] array = {""};
public static ArrayList<String> lst;
ArrayAdapter<String> adapter;
ListView userList;
OutputStream outputStream;
int receivedPort;
InetAddress receivedIP;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
infoip = (TextView) findViewById(R.id.infoip);
msg = (TextView) findViewById(R.id.msg);
userInput = (EditText) findViewById(R.id.userInput);
sendButton = (Button) findViewById(R.id.sendButton);
usersTitle = (TextView) findViewById(R.id.usersTitle);
server = new Server(this);
infoip.setText(server.getIpAddress() + ":" + server.getPort());
userList = (ListView) findViewById(R.id.userList);
lst = new ArrayList<String>(Arrays.asList(array));
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, lst);
userList.setAdapter(adapter);
userList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String selected = userList.getItemAtPosition(position).toString();
msg.append("\n" + selected + " Client Port: " + receivedPort + " Client IP: " + receivedIP );
}
}
);
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String input = userInput.getText().toString();
Socket socket = null;
try {
socket = new Socket("192.168.1.11",receivedPort);
outputStream = new ObjectOutputStream(socket.getOutputStream());
outputStream.write(input.getBytes());
msg.append(socket.getOutputStream().toString());
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
public int getClientPort(int port){
receivedPort = port;
return receivedPort;
}
public InetAddress getClientIP(InetAddress ip){
receivedIP = ip;
return receivedIP;
}
#Override
protected void onDestroy() {
super.onDestroy();
server.onDestroy();
}
}
My server class:
public class Server {
MainActivity activity;
ServerSocket serverSocket;
String message = "";
static final int socketServerPORT = 8080;
public Server(MainActivity activity) {
this.activity = activity;
Thread socketServerThread = new Thread(new SocketServerThread());
socketServerThread.start();
}
public int getPort() {
return socketServerPORT;
}
public void onDestroy() {
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerThread extends Thread {
int count = 0;
#Override
public void run() {
try {
// create ServerSocket using specified port
serverSocket = new ServerSocket(socketServerPORT);
while (true) {
// block the call until connection is created and return
// Socket object
final Socket socket = serverSocket.accept();
count++;
message += " #" + count + " from " + socket.getInetAddress() + ":" + socket.getPort() + "\n"
+ " Host Name: " + socket.getInetAddress().getHostName() + "\n";
final String host = socket.getInetAddress().getHostName();
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
activity.msg.setText(message);
activity.lst.add(host);
activity.adapter.notifyDataSetChanged();
activity.usersTitle.setText("Connected Users (" + count + ")");
activity.getClientIP(socket.getInetAddress());
activity.getClientPort(socket.getPort());
}
});
SocketServerReplyThread socketServerReplyThread =
new SocketServerReplyThread(socket, count);
socketServerReplyThread.run();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerReplyThread extends Thread {
private Socket hostThreadSocket;
int cnt;
SocketServerReplyThread(Socket socket, int c) {
hostThreadSocket = socket;
cnt = c;
}
#Override
public void run() {
OutputStream outputStream;
String msgReply = " Hello from Server, you are #" + cnt;
try {
outputStream = hostThreadSocket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
printStream.print(msgReply);
printStream.close();
message += " replied: " + msgReply + "\n";
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
activity.msg.setText(message);
}
});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
message += " Something wrong! " + e.toString() + "\n";
}
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
activity.msg.setText(message);
}
});
}
}
public String getIpAddress() {
String ip = "";
try {
Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
.getNetworkInterfaces();
while (enumNetworkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = enumNetworkInterfaces
.nextElement();
Enumeration<InetAddress> enumInetAddress = networkInterface
.getInetAddresses();
while (enumInetAddress.hasMoreElements()) {
InetAddress inetAddress = enumInetAddress
.nextElement();
if (inetAddress.isSiteLocalAddress()) {
ip += " Server running at : " + inetAddress.getHostAddress();
}
}
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ip += " Something Wrong! " + e.toString() + "\n";
}
return ip;
}
}
My Client MainACtivity:
public class MainActivity extends Activity {
TextView response;
EditText editTextAddress, editTextPort;
Button buttonConnect, buttonClear, callClass;
Intent intent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editTextAddress = (EditText) findViewById(R.id.addressEditText);
editTextPort = (EditText) findViewById(R.id.portEditText);
response = (TextView) findViewById(R.id.responseTextView);
buttonConnect = (Button) findViewById(R.id.connectButton);
buttonClear = (Button) findViewById(R.id.clearButton);
callClass = (Button) findViewById(R.id.callClass);
callClass.setOnClickListener(
new Button.OnClickListener() {
public void onClick (View v){
intent = new Intent(MainActivity.this, ClientInterface.class);
startActivity(intent);
finish();
}
} );
buttonConnect.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Client myClient = new Client("192.168.1.13", 8080, response);
myClient.execute();
}
});
buttonClear.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
response.setText("");
}
});
}
}
My Client class:
package com.example.seth.chat4all_client;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import android.os.AsyncTask;
import android.widget.TextView;
public class Client extends AsyncTask<Void, Void, Void> {
String dstAddress;
int dstPort;
String response = "";
TextView textResponse;
Client(String addr, int port, TextView textResponse) {
dstAddress = addr;
dstPort = port;
this.textResponse = textResponse;
}
#Override
protected Void doInBackground(Void... arg0) {
Socket socket = null;
try {
socket = new Socket(dstAddress, dstPort);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(
1024);
byte[] buffer = new byte[1024];
int bytesRead;
InputStream inputStream = socket.getInputStream();
/*
* notice: inputStream.read() will block if no data return
*/
while ((bytesRead = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, bytesRead);
response += byteArrayOutputStream.toString("UTF-8");
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "UnknownHostException: " + e.toString();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "IOException: " + e.toString();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
textResponse.setText(response);
super.onPostExecute(result);
}
}
When a message is sent to the client I get this error message:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.seth.chat4all, PID: 9296
android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1147)
at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:110)
at libcore.io.IoBridge.connectErrno(IoBridge.java:137)
at libcore.io.IoBridge.connect(IoBridge.java:122)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:183)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:163)
at java.net.Socket.startupSocket(Socket.java:590)
at java.net.Socket.tryAllAddresses(Socket.java:128)
at java.net.Socket.<init>(Socket.java:178)
at java.net.Socket.<init>(Socket.java:150)
at com.example.seth.chat4all.MainActivity$2.onClick(MainActivity.java:83)
at android.view.View.performClick(View.java:4789)
at android.view.View$PerformClick.run(View.java:19881)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5294)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)

You are trying to do networking on the main thread, which will block any UI actions,
see How to fix android.os.NetworkOnMainThreadException? for the solution to this

Related

how to repeate sending value by socket

I have this client and server communication program. I got the idea from Android-er website.
This codes send a one random number when the customer pressing the connection button and I want to send new random number of every five minutes when the client had been connected with server.
Client code:
public class MainActivity extends AppCompatActivity {
TextView textResponse;
EditText editTextAddress, editTextPort;
Button buttonConnect, buttonClear;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editTextAddress = (EditText)findViewById(R.id.address);
editTextPort = (EditText)findViewById(R.id.port);
buttonConnect = (Button)findViewById(R.id.connect);
buttonClear = (Button)findViewById(R.id.clear);
textResponse = (TextView)findViewById(R.id.response);
buttonConnect.setOnClickListener(buttonConnectOnClickListener);
buttonClear.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
textResponse.setText("");
}});
}
View.OnClickListener buttonConnectOnClickListener = new View.OnClickListener(){
#Override
public void onClick(View arg0) {
MyClientTask myClientTask = new MyClientTask(
editTextAddress.getText().toString(),
Integer.parseInt(editTextPort.getText().toString()));
myClientTask.execute();
}};
public class MyClientTask extends AsyncTask<Void, Void, Void> {
String dstAddress;
int dstPort;
String response = "";
MyClientTask(String addr, int port){
dstAddress = addr;
dstPort = port;
}
#Override
protected Void doInBackground(Void... arg0) {
Socket socket = null;
try {
socket = new Socket(dstAddress, dstPort);
ByteArrayOutputStream byteArrayOutputStream =
new ByteArrayOutputStream(1024);
byte[] buffer = new byte[1024];
int bytesRead;
InputStream inputStream = socket.getInputStream();
/*
* notice:
* inputStream.read() will block if no data return
*/
while ((bytesRead = inputStream.read(buffer)) != -1){
byteArrayOutputStream.write(buffer, 0, bytesRead);
response += byteArrayOutputStream.toString("UTF-8");
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "UnknownHostException: " + e.toString();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "IOException: " + e.toString();
}finally{
if(socket != null){
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
textResponse.setText(response);
super.onPostExecute(result);
}
}
}
and this is the code of server:
public class MainActivity extends AppCompatActivity {
TextView info, infoip, msg, randGen;
String message = "";
ServerSocket serverSocket;
String vRand="";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
info = (TextView) findViewById(R.id.info);
infoip = (TextView) findViewById(R.id.infoip);
msg = (TextView) findViewById(R.id.msg);
randGen= (TextView)findViewById(R.id.viewRand);
infoip.setText(getIpAddress());
Thread socketServerThread = new Thread(new SocketServerThread());
socketServerThread.start();
}
public String rGenerate() {
Random rand= new Random();
int number= rand.nextInt(500-251)+251;
vRand = String.valueOf(number);
//randGen.setText(vRand);
return vRand;
}
#Override
protected void onDestroy() {
super.onDestroy();
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerThread extends Thread {
static final int SocketServerPORT = 8080;
int count = 0;
#Override
public void run() {
try {
serverSocket = new ServerSocket(SocketServerPORT);
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
info.setText("I'm waiting here: "
+ serverSocket.getLocalPort());
}
});
while (true) {
Socket socket = serverSocket.accept();
count++;
message += "#" + count + " from " + socket.getInetAddress()
+ ":" + socket.getPort() + "\n";
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
msg.setText(message);
}
});
SocketServerReplyThread socketServerReplyThread = new SocketServerReplyThread(
socket, count);
socketServerReplyThread.run();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerReplyThread extends Thread {
private Socket hostThreadSocket;
int cnt;
SocketServerReplyThread(Socket socket, int c) {
hostThreadSocket = socket;
cnt = c;
}
#Override
public void run() {
OutputStream outputStream;
String num =rGenerate();
try {
outputStream = hostThreadSocket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
printStream.print(num);
printStream.close();
message += num + "\n";
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
msg.setText(message);
}
});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
message += "Something wrong! " + e.toString() + "\n";
}
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
msg.setText(message);
}
});
}
}
private String getIpAddress() {
String ip = "";
try {
Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
.getNetworkInterfaces();
while (enumNetworkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = enumNetworkInterfaces
.nextElement();
Enumeration<InetAddress> enumInetAddress = networkInterface
.getInetAddresses();
while (enumInetAddress.hasMoreElements()) {
InetAddress inetAddress = enumInetAddress.nextElement();
if (inetAddress.isSiteLocalAddress()) {
ip += "SiteLocalAddress: "
+ inetAddress.getHostAddress() + "\n";
}
}
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ip += "Something Wrong! " + e.toString() + "\n";
}
return ip;
}
}
You can use handler to perform tasks at specific delay. I assumed you know how to send the random numbers using sockets so i wont mess socket codes
Button button = (Button) findViewById(R.id.start_button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
sendData();
handler.postDelayed(this, 15000);
}
}, 15000);
}
});
private void sendData(){
new Worker().execute();
}
private class Worker extends AsyncTask<Void, Void, String>{
private static final String TAG = "Worker";
#Override
protected String doInBackground(Void... params) {
return "Hello There";
}
#Override
protected void onPostExecute(String s) {
Log.i(TAG, s);
}
}
You can use a Handler to do something in a certain time period. Try this
Handler customHandler = new android.os.Handler();
static final int SOCKET_VERIFY_TIME = 5000; //milliseconds
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
customHandler.postDelayed(updateTimerThread, SOCKET_VERIFY_TIME);
...
}
private Runnable updateTimerThread = new Runnable() {
public void run()
{
if(socket != null) {
if(socket.connected()) {
socket.emit("eventNumber", randNumber);
}
}
customHandler.postDelayed(this, SOCKET_VERIFY_TIME);
}
};
if you want stop updates use this
customHandler.removeCallbacks(updateTimerThread);
In your Client
public class MainActivity extends AppCompatActivity {
TextView textResponse;
EditText editTextAddress, editTextPort;
Button buttonConnect, buttonClear;
Handler customHandler = new android.os.Handler();
static final int SOCKET_VERIFY_TIME = 5000; //milliseconds
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editTextAddress = (EditText)findViewById(R.id.address);
editTextPort = (EditText)findViewById(R.id.port);
buttonConnect = (Button)findViewById(R.id.connect);
buttonClear = (Button)findViewById(R.id.clear);
textResponse = (TextView)findViewById(R.id.response);
buttonConnect.setOnClickListener(buttonConnectOnClickListener);
buttonClear.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
textResponse.setText("");
}});
/***** Events Socket ***********/
socket = IO.socket(new URI(URL_SERVER));
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
yourActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// Socket is connect. Do something here
/******************* Set Handler delay ******************/
customHandler.postDelayed(updateTimerThread, SOCKET_VERIFY_TIME);
/************************************************/
}
});
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
#Override
public void call(final Object... args) {
runOnUiThread(new Runnable() {
#Override
public void run() {
// Socket is disconnect. Do something here
customHandler.removeCallbacks(updateTimerThread); // stop handler updates
}
});
}
})
}
View.OnClickListener buttonConnectOnClickListener = new View.OnClickListener(){
#Override
public void onClick(View arg0) {
MyClientTask myClientTask = new MyClientTask(
editTextAddress.getText().toString(),
Integer.parseInt(editTextPort.getText().toString()));
myClientTask.execute();
}};
private Runnable updateTimerThread = new Runnable() {
public void run()
{
if(socket != null) {
if(socket.connected()) {
socket.emit("eventNumber", randNumber);
}
}
customHandler.postDelayed(this, SOCKET_VERIFY_TIME);
}
};
public class MyClientTask extends AsyncTask<Void, Void, Void> {
String dstAddress;
int dstPort;
String response = "";
MyClientTask(String addr, int port){
dstAddress = addr;
dstPort = port;
}
#Override
protected Void doInBackground(Void... arg0) {
Socket socket = null;
try {
socket = new Socket(dstAddress, dstPort);
ByteArrayOutputStream byteArrayOutputStream =
new ByteArrayOutputStream(1024);
byte[] buffer = new byte[1024];
int bytesRead;
InputStream inputStream = socket.getInputStream();
/*
* notice:
* inputStream.read() will block if no data return
*/
while ((bytesRead = inputStream.read(buffer)) != -1){
byteArrayOutputStream.write(buffer, 0, bytesRead);
response += byteArrayOutputStream.toString("UTF-8");
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "UnknownHostException: " + e.toString();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "IOException: " + e.toString();
}finally{
if(socket != null){
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
textResponse.setText(response);
super.onPostExecute(result);
}
}
}

Unable to verify response from server using Sockets in android

I am working on an android chat application based on sockets. I am using the following code to implement this:
NetClient.java
public class NetClient {
/**
* Maximum size of buffer
*/
public static final int BUFFER_SIZE = 2048;
private Socket socket = null;
private PrintWriter out = null;
private BufferedReader in = null;
private String host = null;
private int port = 3000;
// private int port;
/**
* Constructor with Host, Port
*
* #param host
* #param port
*/
public NetClient(String host, int port) {
this.host = host;
this.port = port;
}
private void connectWithServer() {
Log.e("Server", "Connecting with server");
try {
if (socket == null) {
System.out.println("Socket is null");
socket = new Socket(this.host, this.port);
out = new PrintWriter(socket.getOutputStream());
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void disConnectWithServer() {
Log.e("Server", "Disconnecting with server");
if (socket != null) {
if (socket.isConnected()) {
try {
in.close();
out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void sendDataWithString(String message) {
Log.e("Send data", "Sendind data to server");
if (message != null) {
connectWithServer();
out.write(message);
out.flush();
}
}
public String receiveDataFromServer() {
Log.e("Receive data", "Receivind data from the server");
try {
String message = "";
int charsRead = 0;
char[] buffer = new char[BUFFER_SIZE];
while ((charsRead = in.read(buffer)) != -1) {
message += new String(buffer).substring(0, charsRead);
}
//Log.e("ServerResponse", message);
disConnectWithServer(); // disconnect server
return message;
} catch (IOException e) {
return "Error receiving response: " + e.getMessage();
}
}
}
ChatActivity.java
public class ChatActivity extends Activity {
private EditText edtMsg;
private Button btnSend;
private String serverIpAddress = "192.168.2.250";
private int port = 3000;
private boolean connected = false;
private Handler handler = new Handler();
private BufferedReader in = null;
private PrintWriter out = null;
public static final int BUFFER_SIZE = 2048; // Max. size of buffer
private Socket socket = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
edtMsg = (EditText) findViewById(R.id.edtMessage);
btnSend = (Button) findViewById(R.id.btnSendMessage);
btnSend.setOnClickListener(connectListener);
}
private View.OnClickListener connectListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(),"clicked",Toast.LENGTH_LONG).show();
Log.e("Button", "Button clicked");
if (!connected) {
if (!serverIpAddress.equals("")) {
Thread cThread = new Thread(new ClientThread());
cThread.start();
}
}
}
};
public class ClientThread implements Runnable {
public void run() {
NetClient nc = new NetClient(serverIpAddress, port);
String message = edtMsg.getText().toString().trim();
Log.e("Msg", message);
nc.sendDataWithString(message);
String response = nc.receiveDataFromServer();
Log.e("Server Response ", response);
}
}
}
I am not able to verify whether the data has been posted to server or not as i am getting unexpected result from the server.
Logcat
E/Server Response﹕ [ 12-01 14:56:01.313 302: 1017 V/qcbassboost ]
I think i am doing some mistake in the use of socket.Please help me to resolve the issue.

Utilizing a socket in an android application

I've recently made a simple multicast client - server chat for java, now i am attempting to port the client on android.
The issue i'm facing is about dealing with the socket: the socket is created in a thread (as it'd crash the app otherwise), then i use the socket to istantiate an InputStreamReader and an OutputStreamWriter, however when trying to access any object created this way through a button listener, i'll get a null exception.
Also, if i were to put the two readers outside the thread, they would generate a null exception as well, even if i make sure the socket has been created already inside the thread.
I'd be glad if anybody could help me find out where is the issue, i apology for the messy code
public class ClientActivity extends AppCompatActivity {
public static int PORT = 1050;
public static String ADDRESS = "";
public static String USERNAME = "";
SusListenerThread inT;
public int ID;
public int roomID;
Socket socket = null;
BufferedReader in = null, stdIn = null;
PrintWriter out = null;
InputStreamReader isr;
OutputStreamWriter osw;
String userInput="";
public int mode=1;
public Button Bsend;
public Button Bbroadcast;
public Button Broom;
public EditText editMessage;
public EditText editReplies;
public EditText editRoom;
public TextView txtID;
public TextView txtUsername;
public TextView txtRoom;
public connectSocket coSocket;
public ClientActivity() {
}
public void setStuff(String str, int IDh){
this.ID=IDh;
this.USERNAME=str;
txtID.setText("ID: "+IDh);
txtUsername.setText("Username: "+str);
}
private class SusListenerThread extends Thread{
BufferedReader in = null;
public int ID;
public String username;
public boolean isSet=false;
//public View viiv;
public EditText editReplies;
public TextView txtRoom;
public SusListenerThread(InputStreamReader isr){
//this.viiv=viiv;
//editReplies = (EditText)viiv.findViewById(R.id.editReplies);
//txtRoom = (TextView)viiv.findViewById(R.id.textRoom);
in = new BufferedReader(isr);
//ClientGUI.jTextArea1.append(joj+"\n");
start();
}
#Override
public void run(){
String input="";
getStuff();
while(true)
{
try {
input=in.readLine();
} catch (IOException ex) {
//Logger.getLogger(ListenerThread.class.getName()).log(Level.SEVERE, null, ex);
}
if(input.charAt(0)=='0')
//ClientGUI.jTextArea1.append(input.substring(1)+"\n");
editReplies.append(input.substring(1)+"\n");
else if(input.charAt(0)=='1'){
//ClientGUI.jLabel2.setText("Stanza:"+input.substring(1));
txtRoom.setText("Room: "+input.substring(1));
}
}
}
public void getStuff(){
try {
ID=Integer.parseInt(in.readLine());
username+=in.readLine();
} catch (IOException ex) {
}
isSet=true;
}
}
private class connectSocket extends AsyncTask<Void, Void, Void> {
#Override
protected void onPostExecute(Void result) {
}
#Override
protected Void doInBackground(Void... params) {
try {
socket= new Socket(ADDRESS,PORT);
} catch (IOException e) {
try {
socket = new Socket("127.0.0.1", 1050);
}catch(Exception ex){
e.printStackTrace();
};
}
/*
try{
isr = new InputStreamReader ( socket.getInputStream());
//in = new BufferedReader(isr);
inT=new SusListenerThread(isr);
osw = new OutputStreamWriter ( socket.getOutputStream());
BufferedWriter bw = new BufferedWriter( osw );
out = new PrintWriter (bw, true);
} catch (IOException ex) {}
*/
return null;
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(Void... values) {}
}
private class lilThread extends Thread {
public lilThread(){
start();
}
#Override
public void run(){
try {
socket = new Socket(ADDRESS, PORT);
}catch(Exception e ){
try {
socket = new Socket("79.42.49.56", 1050);
} catch (IOException ex) {ex.printStackTrace();}
}
try {
isr = new InputStreamReader ( socket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
inT=new SusListenerThread(isr);
try {
osw = new OutputStreamWriter ( socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
BufferedWriter bw = new BufferedWriter( osw );
out = new PrintWriter (bw, true);
while(!inT.isSet){
try {
wait(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
setStuff(inT.username.substring(4)/*Mi ritornava nullUtente invece di Utente*/, inT.ID);
try {
wait(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
join();
} catch (InterruptedException e) {
e.printStackTrace();
}
interrupt();
}
}
public void InitializeStuff(){
lilThread lil = new lilThread();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client_activity_gui);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
Bsend = (Button)findViewById(R.id.buttonSenderino);
Bbroadcast = (Button)findViewById(R.id.buttonBroadcast);
Broom = (Button)findViewById(R.id.buttonRoom);
editMessage = (EditText)findViewById(R.id.editMessage);
editReplies = (EditText)findViewById(R.id.editReplies);
editRoom = (EditText)findViewById(R.id.editRoom);
txtID = (TextView)findViewById(R.id.textID);
txtUsername = (TextView)findViewById(R.id.textUsername);
txtRoom = (TextView)findViewById(R.id.textRoom);
this.PORT = getIntent().getExtras().getInt("PORT");
this.ADDRESS = getIntent().getExtras().getString("ADDRESS");
this.USERNAME = getIntent().getExtras().getString("USERNAME");
InitializeStuff();
Bsend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//userInput= (EditText)v.findViewById(R.id.editMessage).getco;
userInput = editMessage.getText().toString();
if (!"".equals(userInput)) {
out.println(3 + userInput);
editMessage.setText("");
}
}
});
Bbroadcast.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mode=0;
txtRoom.setText("Room: Broadcast");
roomID=-1;
out.println(mode);
editMessage.setText("");
}
});
Broom.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mode=2;
try{
roomID=Integer.parseInt(editRoom.getText().toString());
txtRoom.setText("Stanza: "+roomID);
out.println(mode+""+roomID);
editRoom.setText("");
}catch(Exception e){
txtRoom.setText(" Err ");
}
}
});
}
}

why my thread in android run more than once when i open my application more than one?

i have this code in android .my code is for reply to multicast msg.it work normaly when i open this application for first.but i use the button back for android and i open for second,this application work more than one and reply more than one reponse .
public class MainActivity extends Activity {
TextView info, infoip, msg;
String message = "";
ServerSocket serverSocket;
String s;
String ipserver;
String replyip;
int i;
int j;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
info = (TextView) findViewById(R.id.info);
infoip = (TextView) findViewById(R.id.infoip);
msg = (TextView) findViewById(R.id.msg);
i=0;
j=1;
infoip.setText(getIpAddress());
WifiManager manager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
WifiInfo infor =manager.getConnectionInfo();
String addr=infor.getMacAddress();
this.s=addr;
Thread t = new Thread (new SocketServerThread());
if(!t.isAlive()){
t.start();
}
}
#Override
protected void onRestart(){
}
#Override
protected void onDestroy() {
super.onDestroy();
i=1;
j=0;
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerThread extends Thread {
static final int SocketServerPORT = 7000;
int count = 0;
#Override
public void run() {
try {
serverSocket = new ServerSocket(SocketServerPORT);
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
info.setText("\n+I'm waiting here: "
+ serverSocket.getLocalPort()+"\n \n");
}
});
while (true) {
MulticastSocket sock = new MulticastSocket(12345);
InetAddress addr = InetAddress.getByName("224.0.0.1");
sock.joinGroup(addr);
DatagramPacket packet;
byte [] buffer= new byte[256];
packet = new DatagramPacket(buffer, buffer.length);
sock.receive(packet);
String Message = new String (packet.getData(),0,packet.getLength());
replyip =packet.getSocketAddress().toString().substring(0, 13);
message+=Message+replyip;
sock.close();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
msg.setText(message);
}
});
SocketServerReplyThread socketServerReplyThread = new SocketServerReplyThread(replyip, count);
if(i==0 )
{
socketServerReplyThread.run();
}
if(j==0){
socketServerReplyThread.run();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerReplyThread extends Thread {
String ips;
SocketServerReplyThread(String ip, int c) {
ips=ip;
}
#Override
public void run() {
try {
Socket s=new Socket(ips.toString(),12345);
DataOutputStream dos =new DataOutputStream(s.getOutputStream());
TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
String a = telephonyManager.getDeviceId();
dos.writeUTF(a);
dos.flush();
dos.close();
s.close();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
msg.setText(message);
}
});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
message += "Something wrong! " + e.toString() + "\n";
}
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
msg.setText(message);
}
});
}
}
private String getIpAddress() {
String ip = "";
try {
Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
.getNetworkInterfaces();
while (enumNetworkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = enumNetworkInterfaces
.nextElement();
Enumeration<InetAddress> enumInetAddress = networkInterface
.getInetAddresses();
while (enumInetAddress.hasMoreElements()) {
InetAddress inetAddress = enumInetAddress.nextElement();
if (inetAddress.isSiteLocalAddress()) {
ip += "SiteLocalAddress: "
+ inetAddress.getHostAddress() + "\n";
}
}
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ip += "Something Wrong! " + e.toString() + "\n";
}
return ip;
}
}
When you press the back button your Application is still in-memory (verify with "adb shell ps"). When you start it again your onCreate gets called. Now you have two instances of SocketServerThread consuming the incoming connections.
Android destroys and recreates the Activity for lots of reasons you might not expect, for example when you rotate the screen. So you have to be careful about keeping data in an Activity.
You should move your networking code out of the Activity and into its own class. Use a singleton or factory pattern to make sure there is only one SocketServerThread.
The problem here is while(true) line in your thread's run method. As many times Activity is created, new Thread is being created and its being executed in infinite loop. If you launch app "n" times, n threads will be created.
Note that socketServerReplyThread.run(); call does not starts a Thread. Its a simple method call.
isAlive check in below code is use-less as a new Thread object has created above it.
Thread t = new Thread(new SocketServerThread());
if (!t.isAlive()) {
t.start();
}
To fix this issue, you can have a flag to check whether activity is destroyed or not. and run loop till activity is destroyed. This will make sure that Thread will have no task once activity is destroyed.
while(isDestroyed){
// do task
}
protected void onDestroy() {
super.onDestroy();
isDestroyed = true;
}
I have edited your code below to make sure that multiple threads are not created.
public class MainActivity extends Activity {
TextView info, infoip, msg;
String message = "";
ServerSocket serverSocket;
String s;
String ipserver;
String replyip;
int i;
int j;
private boolean mIsDestroyed = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
info = (TextView) findViewById(R.id.info);
infoip = (TextView) findViewById(R.id.infoip);
msg = (TextView) findViewById(R.id.msg);
i=0;
j=1;
infoip.setText(getIpAddress());
WifiManager manager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
WifiInfo infor =manager.getConnectionInfo();
String addr=infor.getMacAddress();
this.s=addr;
Thread t = new Thread (new SocketServerThread());
if(!t.isAlive()){
t.start();
}
}
#Override
protected void onRestart(){
}
#Override
protected void onDestroy() {
super.onDestroy();
mIsDestroyed = true;
i=1;
j=0;
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerThread extends Thread {
static final int SocketServerPORT = 7000;
int count = 0;
#Override
public void run() {
try {
serverSocket = new ServerSocket(SocketServerPORT);
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
info.setText("\n+I'm waiting here: "
+ serverSocket.getLocalPort()+"\n \n");
}
});
while (mIsDestroyed == false) {
MulticastSocket sock = new MulticastSocket(12345);
InetAddress addr = InetAddress.getByName("224.0.0.1");
sock.joinGroup(addr);
DatagramPacket packet;
byte [] buffer= new byte[256];
packet = new DatagramPacket(buffer, buffer.length);
sock.receive(packet);
String Message = new String (packet.getData(),0,packet.getLength());
replyip =packet.getSocketAddress().toString().substring(0, 13);
message+=Message+replyip;
sock.close();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
msg.setText(message);
}
});
SocketServerReplyThread socketServerReplyThread = new SocketServerReplyThread(replyip, count);
if(i==0 )
{
socketServerReplyThread.run();
}
if(j==0){
socketServerReplyThread.run();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerReplyThread extends Thread {
String ips;
SocketServerReplyThread(String ip, int c) {
ips=ip;
}
#Override
public void run() {
try {
Socket s=new Socket(ips.toString(),12345);
DataOutputStream dos =new DataOutputStream(s.getOutputStream());
TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
String a = telephonyManager.getDeviceId();
dos.writeUTF(a);
dos.flush();
dos.close();
s.close();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
msg.setText(message);
}
});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
message += "Something wrong! " + e.toString() + "\n";
}
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
msg.setText(message);
}
});
}
}
private String getIpAddress() {
String ip = "";
try {
Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
.getNetworkInterfaces();
while (enumNetworkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = enumNetworkInterfaces
.nextElement();
Enumeration<InetAddress> enumInetAddress = networkInterface
.getInetAddresses();
while (enumInetAddress.hasMoreElements()) {
InetAddress inetAddress = enumInetAddress.nextElement();
if (inetAddress.isSiteLocalAddress()) {
ip += "SiteLocalAddress: "
+ inetAddress.getHostAddress() + "\n";
}
}
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ip += "Something Wrong! " + e.toString() + "\n";
}
return ip;
}
}
Try with Singleton pattern as mentioned below:
public class MySingleton implements Runnable {
private static MySingleton sInstance;
private boolean mIsThreadStarted = false;
// Use this method to access object of this class. Only single object of
// this class will be created and thread will be started only once.
public static synchronized MySingleton getInstance() {
if (sInstance == null) {
sInstance = new MySingleton();
}
return sInstance;
}
private MySingleton() {
// Remove below call if you want start it later.
startThread();
}
// Call this method whenever thread is to be started.
public void startThread() {
if (mIsThreadStarted) {
// Already started.
return;
}
Thread t = new Thread(this);
t.start();
mIsThreadStarted = true;
}
#Override
public void run() {
// Your logic here, which should be running continuously.
while (true) {
// This loop will be running continuously till the app is running.
// You will need to Implement Callback/Listener mechanism to pass
// events to Activity.
}
}
}

UDP holepunching: PC-to-Android UDP connection does not work with nonlocal addresses

I wrote a simple UDP transfer between an Android App and Python Server. I know that the system is working because when I try to connect on a local ip address (192.168.X.X), the correct message is sent and recieved. However, this does not work when I try to use a public IP address. Does anyone know why and how I can try to fix this?
I am trying to implement UDP holepunching, having the server act as the target client of the Android one, but I cannot get the 2nd client's UDP packet to the Android one, it never gets picked up on the Android's side. Would having a 2nd machine act as the 2nd client fix this, or is my code incomplete?
Does my provider (T-Mobile) matter for UDP packet communication?
Client (Android):
public class CustomizeGatewayActivity extends ActionBarActivity {
AsyncUDPReceiver aReceive = null;
static TextView recieve = null;
public static class PlaceholderFragment extends Fragment {
EditText addressText, portText, messageText;
Button udpsend, tcpsend;
Socket socket = null;
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(
R.layout.fragment_customize_gateway, container, false);
recieve = (TextView) rootView.findViewById(R.id.textView1);
addressText = (EditText) rootView.findViewById(R.id.editText1);
messageText = (EditText) rootView.findViewById(R.id.editText3);
udpsend = (Button) rootView.findViewById(R.id.UDP);
udpsend.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
AsyncUDPSend aSend = new AsyncUDPSend(addressText.getText().toString(), messageText.getText().toString());
aSend.execute();
}
});
public class AsyncUDPSend extends AsyncTask<Void, Void, Void> {
String address = "";
String message = "";
String response = "";
AsyncUDPSend(String addr, String mes) {
address = addr;
message = mes;
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
DatagramSocket dsocket = null;
try {
dsocket = new DatagramSocket();
dsocket.setSoTimeout(10000);
InetAddress dest = InetAddress.getByName(address);
DatagramPacket packet = new DatagramPacket(message.getBytes(), message.length(), dest, 5001);
dsocket.send(packet);
System.out.println("Sent");
byte[] resp = new byte[1024];
DatagramPacket recv = new DatagramPacket(resp, resp.length);
System.out.println("Waitng for Response");
dsocket.receive(recv);
System.out.println("Received");
response = new String(recv.getData());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "IOException: " + e.toString();
System.out.println(response);
} finally {
if (dsocket != null) {
dsocket.close();
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
recieve.setText(response);
super.onPostExecute(result);
}
}
#Override
protected void onResume() {
super.onResume();
aReceive = new AsyncUDPReceiver();
aReceive.start();
}
#Override
protected void onPause() {
super.onPause();
aReceive.kill();
}
public class AsyncUDPReceiver extends Thread {
boolean keepRunning = true;
String response = "";
Runnable updateText = new Runnable(){
public void run() {
if(aReceive == null && recieve == null)
return;
recieve.setText(response);
}
};
public void run() {
android.os.Debug.waitForDebugger();
System.out.println("running");
DatagramSocket dsock = null;
byte[] message = new byte[1024];
DatagramPacket dpack = new DatagramPacket(message, message.length);
try {
dsock = new DatagramSocket(5002);
System.out.println(dsock.toString());
while(keepRunning) {
dsock.receive(dpack);
response = new String(dpack.getData());
System.out.println(response);
runOnUiThread(updateText);
}
} catch (SocketException e) {
// TODO Auto-generated catch block
response = "SocketException: " + e.toString();
System.out.println(response);
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
response = "IOException: " + e.toString();
System.out.println(response);
e.printStackTrace();
} finally {
if(dsock != null)
dsock.close();
}
}
public void kill() {
keepRunning = false;
}
}
}
Server (Python):
class ThreadedUDPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.request[0].strip().decode("utf-8")
print("{} Recieved: ".format(self.client_address) + data)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
response = data.upper()
sock.sendto(bytes(response, "utf-8"), self.client_address)
print("{} Sent: {}".format(self.client_address,response))
class ThreadedUDPServer(socketserver.ThreadingMixIn, socketserver.UDPServer):
pass
if __name__ == "__main__":
# Port 0 means to select an arbitrary unused port
HOST, PORT = "", 5000
udpserver = ThreadedUDPServer((HOST,PORT+1), ThreadedUDPRequestHandler)
udp_thread = threading.Thread(target=udpserver.serve_forever)
udp_thread.daemon = True
udp_thread.start()
print("UDP serving at port", PORT+1)
while True:
pass
udpserver.shutdown()
Are you supplying the expected value to InetAddress.getByName(address);
Also since you are trying to do something in background,it will be better if you run a service with wake lock so that you eliminate errors caused due to killing of process.

Categories

Resources