I am writing an app that involves Client -> Server -> Client communication (one way traffic). I have my data transmitted from client A to the server, simple to test, just print to console, however, I'm trying to test to see if the data has been sent on to the next client. I have tried a text view, nothing is displaying in this view however, now I don't know if that's because the data hasn't arrived or indeed because I've coded it wrong. I'm not very experienced in android.
I've attached my code below, if anyone can help I would really appreciate it.
Regards,
Gary
public class Parent extends Activity {
private Socket s;
private PrintWriter p;
String location;
double Platitude, Plongitude;
double Clatitude, Clongitude;
double distance;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.parent);
Thread rec = new Thread(new Runnable() {
public void run() {
// TODO Auto-generated method stub
try {
s = new Socket("192.168.1.2", 1980);
InputStream fromServer = s.getInputStream();
while (s.isConnected()) {
Scanner r = new Scanner(fromServer);
if(r.hasNextLine())
{
location = r.nextLine();
}
TextView myTextview = (TextView) findViewById(R.id.dist);
myTextview.setText(location);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
rec.start();
}
Related
OVERVIEW
I'm using Android Studio to make an app that on a button press sends a string to a UDP listener in Node-Red running on my laptop, Node-Red filters anything that comes in and function nodes do their thing. This app will work inside a LAN not over the internet.
So far I have made a new project with an empty activity and my activity_main.xml has the button. There is no need for the user to input a string/text so the button press code will have the "string" and Node-Red listener IP and port hard coded.
There is also no need to receive a reply from the laptop/node-red side so the button press should be a fire and forget hard coded message hence UDP and not a TCP socket.
QUESTION
What code is required for the MainActivity to send the string when the button is pressed to the UDP listener in Node-Red?
I have spent a long time scouring the internet for answers and tried many code examples however they have not worked. A lot of the research I've seen is people with UDP receive problems, however I cannot understand their code for sending UDP.
I finally worked it out with a ridiculous amount of trial and error... please see the code below if anyone else ever gets the same problem:
//On button press the message is sent via UDP
findViewById(R.id.btSendMessage).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int txnumber = Integer.parseInt(((TextView) findViewById(R.id.transmitnumber)).getText().toString());
String data = ((TextView) findViewById(R.id.texttosend)).getText().toString();
int port = Integer.valueOf(((TextView) findViewById(R.id.serverport)).getText().toString());
String address = ((TextView) findViewById(R.id.serverip)).getText().toString();
SendData(txnumber, data, port, address);
}
});
private DatagramSocket UDPSocket;
private InetAddress address;
private int port;
public void Theaddress(InetAddress address) {
try {
this.UDPSocket = new DatagramSocket();
this.address = address;
} catch (SocketException e) {
e.printStackTrace();
}
}
public void SendInstruction(final byte[] data, final int port) {
new Thread() {
#Override
public void run() {
try {
DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
UDPSocket.send(packet);
DatagramPacket packetreponse = null;
UDPSocket.receive(packetreponse);
DisplayData(packetreponse);
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
public void SendData(final int nbRepet, final String Sdata , final int port, final String address) {
new Thread() {
#Override
public void run() {
try {
Theaddress(InetAddress.getByName(address));
for (int i = 0; i < nbRepet; i++) {
byte[] data = Sdata.getBytes();
SendInstruction(data,port);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
public void ReceiveData(final int portNum) {
new Thread() {
#Override
public void run() {
try {
final int tally = 1024;
final byte[] buffer = new byte[tally];
DatagramSocket socketReceive = new DatagramSocket(portNum);
while (true) {
DatagramPacket data = new DatagramPacket(buffer, buffer.length);
socketReceive.receive(data);
DisplayData(data);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
public void DisplayData(DatagramPacket data) {
System.out.println(data);
}
I am trying to develop an android application that can exchange data on peer to peer connection with other devices without server. So please suggest how can I do this. Thank you in advance.
This is a complete code for chat by SocketProgramming without server.
In my Application, first you are a client and you search for a server. When you do not find any server, you become a server and wait for a client.
public class MainActivity extends ActionBarActivity {
private Handler handler = new Handler();
private TextView text;
private EditText input;
private Button send;
private Socket socket;
private DataOutputStream outputStream;
private BufferedReader inputStream;
private String DeviceName = "Device";
private boolean searchNetwork() {
log("Connecting");
String range = "192.168.56.";
for (int i = 1; i <= 255; i++) {
String ip = range + i;
try {
socket = new Socket();
socket.connect(new InetSocketAddress(ip, 9000), 50);
outputStream = new DataOutputStream(socket.getOutputStream());
inputStream = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
DeviceName += "1";
Log.i("Server", DeviceName);
log("Connected");
return true;
} catch (Exception e) {
}
}
return false;
}
private void runNewChatServer() {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(9000);
log("Waiting for client...");
socket = serverSocket.accept();
DeviceName += "2";
log("a new client Connected");
} catch (IOException e) {
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
input = (EditText) findViewById(R.id.input);
send = (Button) findViewById(R.id.send);
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
if (!searchNetwork()) {
runNewChatServer();
}
outputStream = new DataOutputStream(
socket.getOutputStream());
inputStream = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
while (true) {
String Message = inputStream.readLine();
if (Message != null) {
log(Message);
}
}
} catch (IOException e) {
log("Error: IO Exception");
e.printStackTrace();
}
}
});
send.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
if (outputStream == null) {
return;
}
try {
String Message = input.getText().toString() + "\n";
outputStream.write(Message.getBytes());
log2(input.getText().toString());
} catch (IOException e) {
e.printStackTrace();
}
input.setText("");
}
});
thread.start();
}
private void log(final String message) {
handler.post(new Runnable() {
String DeviceName2="";
#Override
public void run() {
if (DeviceName.equals("Device1")) {
DeviceName2 = "Device2";
}else if(DeviceName.equals("Device2")) {
DeviceName2 = "Device1";
}else{
DeviceName2 = "UnknowDevice";
}
text.setText(text.getText() + "\n" + DeviceName2 + " :"
+ message);
}
});
}
private void log2(final String message) {
handler.post(new Runnable() {
#Override
public void run() {
text.setText(text.getText() + "\n" + "you" + " :"
+ message);
}
});
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.exit(0);
return true;
}
return super.onKeyDown(keyCode, event);
}
}
Your design has a big problem : ...
If there is no central server some android devices should act as client and others as server but this will not work in some situations:
When the mobile telephony provider assigns private and non-public IP
When the device is connected to a Wi-Fi network but no NAT rule is defined on the router.
In both cases the problem is that the listening port of the device that must act as server is unreachable.
Java provides ServerSocket and Socket to communicate b/w devices. One of the device you can make as server and other device you can make as client and communicate b/w 'em without introducing server hosted on some machine.
The Other and better option is Using Wi-Fi Peer-to-Peer. WifiP2pManager help you to achieve your purpose.Here is an example.
If you're looking for such P2P over a local network, there are two parts to it:
Discovering peers
Communicating with peers
Among Android APIs, you can either use Network Service Discovery APIs for this or Wifi P2P Service Discovery APIs.
There's a wrapper library which which uses these internally and has comparatively better documentation - Salut, which can also be used.
I also created a library for P2P - Near, which uses sockets directly. The problem I was facing with Android APIs was that discovery wasn't happening with certainty every time and the underlying issue was unknown.
If you're looking for P2P across the internet, socket IO is a prevalent solution. Even Near should be able to facilitate the transfers if you provide the IP addresses and they're not behind NAT firewalls.
I am trying to show two consecutive images in an Android app, which are received through a socket (from a C program using sendfile). The sender code seems to work ok, and I am having issues with the Android code side.
Part of the code in the Android app is the following:
public class DisplayNewActivity extends Activity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
....
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
Drawable d2;
d2 = (Drawable)msg.obj;
imageSock.setImageDrawable(d2); // to set the arrived image in the imageshow object
}
};
...
cThread = new Thread(new ClientThread());
rThread = new Thread(new RcvThread());
cThread.start();
}
public class ClientThread implements Runnable {
public void run() {
// thread used for socket connection.
...
rThread.start(); // once the connection has been established
...
}
}
#SuppressLint("HandlerLeak")
public class RcvThread implements Runnable {
public void run() {
while (connected) {
try {
InputStream inputStream = socket.getInputStream();
Drawable d = Drawable.createFromStream(inputStream, null);
Message msg = new Message();
msg.obj = d;
mHandler.sendMessage(msg);
} catch (Exception e) {
Log.e("SocketConnectionv02Activity", "C: ErrorRCVD", e);
}
}
}
}
}
The problem I am facing is that after the first image received by the Android app is shown correctly, then the next one received (which is correctly received) is not shown and leaves the imageview object showing a white space.
Any suggestion/idea to solve this issue?.
Thanks in advance for any help you could provide.
EDIT:
public class DisplayNewActivity extends Activity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
....
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
Bitmap d2;
d2 = (Bitmap)msg.obj;
imageSock.setImageBitmap(d2); // to set the arrived image in the imageshow object
}
};
...
cThread = new Thread(new ClientThread());
rThread = new Thread(new RcvThread());
cThread.start();
}
public class ClientThread implements Runnable {
public void run() {
// thread used for socket connection.
...
rThread.start(); // once the connection has been established
...
}
}
#SuppressLint("HandlerLeak")
public class RcvThread implements Runnable {
public void run() {
while (connected) {
try {
DataInputStream in = new DataInputStream(socket.getInputStream());
Bitmap d = BitmapFactory.decodeStream(in);
Message msg = new Message();
msg.obj = d;
mHandler.sendMessage(msg);
} catch (Exception e) {
Log.e("SocketConnectionv02Activity", "C: ErrorRCVD", e);
}
}
}
}
}
It sounds like the issue you are having is in decoding the data into a proper image after receiving it.
I might recommend not using Drawable.createFromStream() and instead using BitmapFactory.decodeStream() or manually downloading the data into a byte[] first and using BitmapFactory.decodeByteArray(). Sometimes the latter is useful if the former can't sufficiently keep up with the decoder as the data is received.
The method you are currently using actually ends up calling BitmapFactory.descodeResourceStream(), which is used to read image data out of the local res/ package and not so much from a remote socket.
I'm not the best programmer, actually, I'm pretty bad :(
I need help with something thats driving my crazy. basically I have a tcpdump process, I want to extract the output and put it into a textview which is updated every few milliseconds, I've tried everything and just cant get it to work.
I don't get any errors and it seems to work in the background, but only displays chunks of text only after I go to the homescreen and return back into the app. however, it doesnt constantly update the textview, and sometimes hangs and crashes.
I've created a simple handler which can update the textview with plain text without problems, but then i faced major problems getting it to read the process.
Begin button
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.capture);
this.LiveTraffic = (TextView) findViewById(R.id.LiveTraffic);
this.CaptureText = (TextView) findViewById(R.id.CaptureText);
((TextView) findViewById(R.id.ipv4)).setText(getLocalIpv4Address());
((TextView) findViewById(R.id.ipv6)).setText(getLocalIpv6Address());
//Begin button
final Button startButton = (Button) findViewById(R.id.start);
startButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Now Capturing Packets", Toast.LENGTH_LONG).show();
try {
process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("/data/local/tcpdump -q\n");
os.flush();
os.writeBytes("exit\n");
os.flush();
os.close();
inputStream = new DataInputStream(process.getInputStream());
Thread.sleep(1000);
Process process2 = Runtime.getRuntime().exec("ps tcpdump");
DataInputStream in = new DataInputStream(process2.getInputStream());
String temp = in.readLine();
temp = in.readLine();
temp = temp.replaceAll("^root *([0-9]*).*", "$1");
pid = Integer.parseInt(temp);
Log.e("MyTemp", "" + pid);
process2.destroy();
CaptureActivity.this.thisActivity.CaptureText.setText("Active");
} catch (Exception e) {
}
ListenThread thread = new ListenThread(new BufferedReader(new InputStreamReader(inputStream)));
thread.start();
}
});
}
ListenThread class
public class ListenThread extends Thread {
public ListenThread(BufferedReader reader) {
this.reader = reader;
}
private BufferedReader reader = null;
#Override
public void run() {
reader = new BufferedReader(new InputStreamReader(inputStream));
while (true) {
try {
CaptureActivity.this.thisActivity.CaptureText.setText("exec");
int a = 1;
String received = reader.readLine();
while (a == 1) {
CaptureActivity.this.thisActivity.LiveTraffic.append(received);
CaptureActivity.this.thisActivity.LiveTraffic.append("\n");
received = reader.readLine();
CaptureActivity.this.thisActivity.CaptureText.setText("in loop");
}
CaptureActivity.this.thisActivity.CaptureText.setText("out loop");
} catch (Exception e) {
Log.e("FSE", "", e);
}
}
}
}
I am not an android expert but I notice that:
you are running I/O operations in the UI thread - that will freeze your GUI until the I/O operation finishes ==> run them in a separate thread.
you update the UI from outside the UI thread in ListenThread, which can lead to unexpected results
You can read more about it in this tutorial (make sure you read the 2 examples as the first one is broken (on purpose)).
EDIT
In conclusion you should have something like this in your first piece of code:
startButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Now Capturing Packets", Toast.LENGTH_LONG).show();
new Thread(new Runnable() {
public void run() {
try {
process = Runtime.getRuntime().exec("su");
...
CaptureActivity.this.runOnUiThread(new Runnable() {
public void run() {
CaptureActivity.this.thisActivity.CaptureText.setText("Active");
}
});
} catch (Exception e) {
}
ListenThread thread = new ListenThread(new BufferedReader(new InputStreamReader(inputStream)));
thread.start();
}
}).start();
}
});
and in the second:
while (true) {
try {
CaptureActivity.this.runOnUiThread(new Runnable() {
public void run() {
CaptureActivity.this.thisActivity.CaptureText.setText("exec");
}
});
int a = 1;
String received = reader.readLine();
while (a == 1) {
CaptureActivity.this.runOnUiThread(new Runnable() {
public void run() {
CaptureActivity.this.thisActivity.LiveTraffic.append(received);
CaptureActivity.this.thisActivity.LiveTraffic.append("\n");
CaptureActivity.this.thisActivity.CaptureText.setText("in loop");
}
});
received = reader.readLine();
}
CaptureActivity.this.runOnUiThread(new Runnable() {
public void run() {
CaptureActivity.this.thisActivity.CaptureText.setText("out loop");
}
});
} catch (Exception e) {
Log.e("FSE", "", e);
}
}
That should solve the specific UI interaction issue. But there are other logic problems in your code which go beyond this question (for example the fact that you never test if you have reached the end of the file you are reading, the fact that while(a==1) is an infinite loop because you never change the value of a etc.).
im trying to implement a tcp socket connection between an android app (as server) and a java based client running on windows. (short version below, without code)
Im using some sensor listener to implement a game movement (everybody knows this sensor based movement of racing games.
Ive implemented a service for that purpose, which is started out of the first activity. This service is implemented as follows (im just pasting the relevant code snippets, not the whole class):
public class ServerService extends Service {
ConnectionHandler conHandler;
#Override
public void onCreate() {
startListener();
}
private void startListener() {
conHandler = new ConnectionHandler(this);
conHandler.execute();
}
private void sendMessage(String s)
{
conHandler.write(s);
}
public void messageNotify(String s) {
//Log.d("receivedMessage", s);
}
}
The ConnectionHandler class:
public class ConnectionHandler extends AsyncTask<Void, Void, Void>{
public static int serverport = 11111;
ServerSocket s;
Socket c;
ConnectionListening conListening;
ConnectionWriting conWriting;
DataOutputStream dos;
DataInputStream dis;
ServerService server;
public ConnectionHandler(ServerService server)
{
this.server = server;
}
#Override
protected Void doInBackground(Void... params) {
try {
Log.i("AsyncTank", "doInBackgoung: Creating Socket");
s = new ServerSocket(serverport);
} catch (Exception e) {
Log.i("AsyncTank", "doInBackgoung: Cannot create Socket");
}
try {
//this is blocking until client connects
c = s.accept();
Log.d("ConnectionHandler", "client connected");
dis = new DataInputStream(c.getInputStream());
dos = new DataOutputStream(c.getOutputStream());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
conWriting = new ConnectionWriting(this.c, this.dos);
conWriting.execute();
conListening = new ConnectionListening(this.c, this.dis, this.server);
if(this.c != null)
{
Timer timer = new Timer();
timer.schedule(conListening, 0, 10);
}
Log.i("AsyncTank", "doInBackgoung: Socket created, Streams assigned");
return null;
}
public void write(String s)
{
conWriting.writeToStream(s);
}
public void messageNotify(String s) {
// TODO method stub
}
}
The ConnectionHandler ist implemented as AsyncTask similarly to the ConnectionWriting, so that the blocking of tcp methods doenst affect the whole communication.
The client is able to send messages to the server to. Because i dont know when this messages will arrive, im using a TimerTask which is executed every 10ms, to check if there is a new message.
ConnectionWriting looks as follows:
public class ConnectionWriting extends AsyncTask<Context, Void, Boolean>{
public DataOutputStream dos;
Socket c;
public ConnectionWriting(Socket c, DataOutputStream dos) {
this.dos = dos;
this.c = c;
}
#Override
protected Boolean doInBackground(Context... params) {
return true;
}
public void writeToStream(String s) {
try {
if (c != null){
//Log.i("AsynkTask", "writeToStream");
dos.writeBytes(s+"\n");
dos.flush();
Log.i("AsynkTask", "write: " +s);
} else {
Log.i("AsynkTask", "writeToStream : Cannot write to stream, Socket is closed");
}
} catch (Exception e) {
Log.i("AsynkTask", "writeToStream : Writing failed");
}
}
}
And the ConnectionListening class:
public class ConnectionListening extends TimerTask{
public DataInputStream dis;
Socket c;
ServerService server;
public ConnectionListening(Socket c, DataInputStream dis, ServerService server)
{
this.c = c;
this.dis = dis;
this.server = server;
}
#Override
public void run() {
String message = "";
try {
if (c != null) {
//Log.i("AsynkTask", "readFromStream : Reading message");
message = dis.readLine();
Log.i("AsynkTask", "read: " + message);
} else {
Log.i("AsynkTask", "readFromStream : Cannot Read, Socket is closed");
}
} catch (Exception e) {
Log.i("AsynkTask", "readFromStream : Writing failed");
}
if(message != null)
{
this.server.messageNotify(message);
}
}
}
I choose this complex, asynchronous way because the server is almost continuous sending data to the client and there are situations where the client has to send data back.
With the traditional way of using tcp sockets, it is not possible to realise a non blocking communication, so that means if the server is sending (writing), the read function blocks and i will never get the client message.
to keep it short:
Ive tested my approach but the server is always sending his data first and then getting the client messages. It is not asynchronous!? :-/
Maybe anybody can help me to solve this problem.
Or is there even a simpler way to implement that approach?
It is necessary that the communication is asynchronous! And the read has to be done automatically (what i tried to implement with this polling approach).
Ive read that i can use a single thread for the reading and one for the writing, but then i have a problem with using the write functionality (dont know how to call a function in a running thread) and with calling functions in my activities.
Im thankful for every help!
regards