I'm starting to code with MulticastSocket, trying to make a simple app with a client and a server to send messages.
The code I have for the server:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.SocketException;
public class Servidor {
private static MulticastSocket ms;
public static void main(String[] args) throws IOException{
InetAddress sessAddr = InetAddress.getByName("224.2.76.24");
try{
sessAddr = InetAddress.getByName("224.2.76.24");
ms = new MulticastSocket(5500);
ms.joinGroup(sessAddr);
while (true)
{
byte[] mensaje = new byte[1024];
mensaje = "aa".getBytes();
DatagramPacket dp = new DatagramPacket(mensaje, mensaje.length,sessAddr,5500);
ms.send(dp);
}
}
catch (SocketException se) {
System.err.println(se);
}
ms.leaveGroup(sessAddr);
}
}
And this on the client:
package com.example;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.os.Bundle;
import android.widget.EditText;
import android.widget.TextView;
public class ClienteMultiCast extends Activity {
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView Mensaje;
Mensaje =(TextView)findViewById(R.id.Mensaje);
InetAddress ia = null;
byte[] buffer = new byte[65535];
MulticastSocket ms = null;
int port = 5500;
try {
ia = InetAddress.getByName("224.2.76.24");
DatagramPacket dp = new DatagramPacket(buffer, buffer.length,ia,port);
ms = new MulticastSocket(port);
ms.joinGroup(ia);
while (true) {
ms.receive(dp);
String s = new String(dp.getData(),0,dp.getLength());
Mensaje.setText(s);
}
} catch (UnknownHostException e) {Mensaje.setText(e.getMessage());} catch (IOException e) {Mensaje.setText(e.getMessage()); }
try {
ms.leaveGroup(ia);
} catch (IOException e) {
Mensaje.setText(e.getMessage());
}
}
}
The problem is that when I start both, nothing happens. The client doesn't get any message.
Any idea what's wrong?
Diego,
By default, the Android WiFi stack filters out multicast packets. Take a look at http://developer.android.com/reference/android/net/wifi/WifiManager.MulticastLock.html.
You need something along the lines of:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* Turn off multicast filter */
MulticastLock mcastLock = new MulticastLock();
mcastLock.acquire();
/* Process Multicast Packets */
}
It appears that Multicast support in Android is not as solid as some of use might hope. See http://codeisland.org/2012/udp-multicast-on-android/
Ie whether it actually works out or may be device dependent. It is not working on my Nexus5.
https://code.google.com/p/android/issues/detail?id=51195
Related
This question already has answers here:
NetworkOnMainThreadException [duplicate]
(5 answers)
Closed 6 years ago.
I'm trying to test if my Android App is connecting to a Rpi hot spot. I'm following this guide for the client code.
I want to have a toast message pop up depending on the state of socket.isConnected() when I hit a button. However, I think each time I try and implement it, I run into Network on the main thread problems. How could I change the following code to add a simple "if(true), send toast message" using the isConnected method in the onClick?
Thank you for any help!
package mrxhaleenterprise.sockettest;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private Socket socket;
private static final int SERVERPORT = 39169;
private static final String SERVER_IP = "172.24.1.1";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new ClientThread()).start();
}
public void onClick(View view) {
try {
EditText et = (EditText) findViewById(R.id.EditText01);
String str = et.getText().toString();
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
out.println(str);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
class ClientThread implements Runnable {
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
onClick is called on main Thread.So you are writing to socket(Network Operation) on main thread which is causing problem. Your below code should run on background thread.
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
out.println(str);
I want to have a toast message pop up depending on the state of socket.isConnected() when I hit a button.
No you don't. Once you've constructed that Socket, it is connected, and that method won't magically start returning false if the connection goes down. You need to maintain your own state of the connection, depending on whether you've encountered an IOException or end of stream on it. More probably you don't want the button at all, you want to pop up an error dialogue when the disconnect happens.
I can't receive any packets on my app. I have a computer running from console-php this script:
$broadcast_string='http://hellokitty/shownumber.html';
$port=2328;
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_set_option($sock, SOL_SOCKET, SO_BROADCAST, 1);
while(true){
socket_sendto($sock, $broadcast_string, strlen($broadcast_string), 0, '255.255.255.255', $port);
sleep(1);
echo "Broadcasting ...\n";
}
on the other hand I got this code running on my phonegap app on the MainActivity.java file:
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.content.Context;
import org.apache.cordova.*;
import java.io.*;
import java.net.*;
import java.util.*;
import android.content.BroadcastReceiver;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.os.Environment;
import android.content.Context;
import android.app.DialogFragment;
import android.app.AlertDialog;
import android.view.Menu;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.provider.Settings;
import android.view.WindowManager;
import android.util.Log;
import android.content.res.AssetManager;
public class MainActivity extends CordovaActivity
{
public static String URL = null;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
try {
DatagramSocket socket;
//Wakelock------------------------------------------------------------------------------------------------------------------
WakeLock mWakeLock = null,mPartialWakeLock = null;
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
// lock used to keep the processor awake.
mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG);
mPartialWakeLock.acquire();
final WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock lock = wifi.createMulticastLock("UDP");
lock.acquire();
//--------------------------------------------------------------------------------------------------------------------------
try {
//Keep a socket open to listen to all the UDP trafic that is destined for this port
//socket = new DatagramSocket(2328, InetAddress.getByName("0.0.0.0"));
socket = new DatagramSocket(2328);
socket.setBroadcast(true);
URL = null;
while (URL == null) {
System.out.println(getClass().getName() + ">>>Ready to receive broadcast packets!");
//Receive a packet
byte[] recvBuf = new byte[12000];
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
//socket.setSoTimeout(10000);
socket.receive(packet);
//Packet received
System.out.println(getClass().getName() + ">>>Discovery packet received from: " + packet.getAddress().getHostAddress());
System.out.println(getClass().getName() + ">>>Packet received; data: " + new String(packet.getData()));
String message = new String(packet.getData()).trim();
URL=message;
break;
}
} catch (IOException ex) {
//Nothing
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
while(URL == null){
continue;
}
Log.d("net_discover",URL);
super.loadUrl(URL);
}
}
I've tested the network sniffing packets and traffic it's ok.
I've added the wakelock section since I've read that android blocks broadcast packets, but I'm still not getting anything on my device.
I'm working on a Motorola running Android 4.4.4
On the adb logcat, app is stuck on the msg "Ready to receive.." and that's all I get.
Any suggestions?
UPDATE:
I added code to my app to send packet before starting receiving and for my surprise it does receive it. So I started sending packets and sniffing the network from my computer and I don't see any. So doing some more research I found that the app is working on the lo interface (loopback, 127.0.0.1).
So my question now is, how do I make the app receive packets from wifi interface?
I have built a upd server listen code to upload on my phone and listen to data packets. This code will compile but for some reason it wont load to my phone. I don't see any errors anywhere. Why could this be ? this is my whole Mainactivity code :
package roman10.tutorial.udpcommserver;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.net.InetSocketAddress;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class UdpServer extends Activity {
/** Called when the activity is first created. */
private TextView textView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView) findViewById(R.id.text1);
runUdpServer();
}
private static final int UDP_SERVER_PORT = 4000;
private static final int MAX_UDP_DATAGRAM_LEN = 1500;
private static final String ipAdd = new String("172.30.42.80");
private void runUdpServer() {
String lText;
// byte[] lMsg = new byte[MAX_UDP_DATAGRAM_LEN];
// DatagramPacket dp = new DatagramPacket(lMsg, lMsg.length);
// DatagramSocket ds = null;
byte buffer[] = new byte[MAX_UDP_DATAGRAM_LEN];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
try {
// ds = new DatagramSocket(UDP_SERVER_PORT);
// //disable timeout for testing
// //ds.setSoTimeout(100000);
// ds.receive(dp);
//lText = new String(lMsg, 0, dp.getLength());
// Log.i("UDP packet received", lText);
// textView.setText(lText);
DatagramSocket s = new DatagramSocket();
InetSocketAddress address = new InetSocketAddress(ipAdd, UDP_SERVER_PORT);
s.bind(address);
lText = new String(buffer,0,packet.getLength());
Log.i("UDP packet received", lText);
textView.setText(lText);
System.out.println("Waiting...");
s.receive(packet);
if (s != null) {
s.close();
}
// s.close();
System.out.println("Received!");
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
System.out.print("we are done ");
}
}
}
1)
You are not returning from your onCreate (until you have received something). The activity can't continue to start (certainly not call onStart, onResume etc.
2)
Then you are doing I/O on the main thread, network I/O even, not recommended and usually detected as not allowed on android and force closed. You will get a NetworkOnMainThreadException
Fortunately both those issues can be solved by creating a separate thread and executing runUdpServer() there.
Short example, instead of:
runUdpServer();
do:
Thread thread = new Thread() {
public void run() {
runUdpServer();
}
};
thread.start();
This question already has answers here:
Java multiple file transfer over socket
(3 answers)
Closed 7 years ago.
I'm developing an application and I want to transfer files from a computer to a phone using sockets. I'm able to transfer one file but when I want to transfer multiple files, they pile up. Here's how the program works:
I get a screenshot from computer using Robot.
I save it as Send.jpg.
I send the image. Let's say for example its size is 1 MB.
I receive the image on phone.
I display it in an ImageView.
And loop through these steps again until the user closes the activity on phone.
But the result is this :
I get the first screenshot (Send.jpg: 1 MB) send it and receive it on phone. Get the second one (Send.jpg: 2 MB) send it and receive it on phone. and the third one and etc...
It never gets displayed on phone. And when I check the phone storage using explorer, I see one image - its size is the size of the first image + the second + the third ...
I guess my problem is i have to stop the InputStream, please help.
Code :
Server :
package application;
import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import javax.imageio.ImageIO;
public class ScreenCapture {
Socket socket;
OutputStream os;
Robot robot;
PrintStream ps;
public ScreenCapture() throws IOException, AWTException {
// TODO Auto-generated constructor stub
socket = SocketWrapper.getSocket();
os = socket.getOutputStream();
robot = new Robot();
ps = new PrintStream(socket.getOutputStream());
new Record().start();
}
private class Record extends Thread{
#Override
public void run() {
while(true){
int count;
Rectangle rect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage img = robot.createScreenCapture(rect);
try {
ImageIO.write(img, "jpg", new File("/Users/Tomahawk/Documents/MovieMaker/send.jpg"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
FileInputStream fis;
try {
File f = new File("/Users/Tomahawk/Documents/MovieMaker/send.jpg");
fis = new FileInputStream(f);
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] byteArray = new byte[(int) f.length()];
long filesize = f.length();
while((count = bis.read(byteArray)) > 0){
os.write(byteArray,0,count);
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("Sent File");
}
}
}
}
Client (Phone) :
package com.pcontrol.tomahawk.pcontrol;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ScreenCapture extends Activity {
Socket socket;
InputStream is;
OutputStream os;
Scanner scanner;
ImageView screenCap;
long filesize = 0;
int i=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_capture);
socket = SocketWrapper.getSocket();
try {
is = socket.getInputStream();
scanner = new Scanner(is);
} catch (IOException e) {
e.printStackTrace();
}
screenCap = (ImageView) findViewById(R.id.screenCap);
new ReceiveFiles().execute();
}
private class ReceiveFiles extends AsyncTask<Void,Void,Void> {
#Override
protected Void doInBackground(Void... params) {
try {
os = new FileOutputStream("/sdcard/"+i+".jpg");
copy(is, os);
publishProgress();
} catch (IOException e) {
e.printStackTrace();
}
i++;
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
Bitmap bmp = BitmapFactory.decodeFile("/sdcard/"+i+".jpg");
screenCap.setImageBitmap(bmp);
}
}
static void copy(InputStream in, OutputStream out) throws IOException {
byte[] buf = new byte[60000];
int len = 0;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_screen_capture, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
You're not telling the receiver where one file ends and the next one starts.
You could add a basic framing protocol, for example one where you first send the size of the file and then the data. That way the receiver can count the bytes it reads and knows when to close the current file and open another.
Alternatively you could use separate sockets to send each file, but it looks like that would require major changes to your architecture.
So for my research, I have to send accelometer data to an arduino mega as a constant stream. I have the module connected to the arduino via serial. However, when I ran the code, it only runs once. I tried to place the Bluetooth connect part of the code inside my on accuracy change part of my code, but it keeps freezing the device. Here's my code:
package com.example.arduino_bluetooth2;
//=================================================================================================
//Imports
//=================================================================================================
import java.io.IOException;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;
import android.os.Bundle;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.Menu;
import android.widget.TextView;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
public class MainActivity extends Activity implements SensorEventListener {
// Setup necessary sensor objects
private Sensor acc;
private SensorManager sm;
private TextView t1;
private double value;
// Bluetooth Object
private BluetoothAdapter bAdapter;
private BluetoothDevice device;
private BluetoothSocket mmServerSocket;
private OutputStream btoutput;
private static final UUID SPP_UUID = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static final int DISCOVERY_REQUEST = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
accelerometer_initialization();
bluetooth_initialization();
}
// Setsup the accelerometer object
private void accelerometer_initialization() {
sm = (SensorManager) getSystemService(SENSOR_SERVICE);
acc = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sm.registerListener(this, acc, SensorManager.SENSOR_DELAY_NORMAL);
}
// Setup bluetooth object
private void bluetooth_initialization() {
bAdapter = BluetoothAdapter.getDefaultAdapter();
startActivityForResult(new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE),
DISCOVERY_REQUEST);
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
bAdapter.startDiscovery();
}
#Override
public void onSensorChanged(SensorEvent event) {
value = event.values[0];
}
#Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
}
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) {
device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (new String(device.getName()).equals("BT UART")) {
bAdapter.cancelDiscovery();
try {
BluetoothSocket test = null;
test = device
.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
mmServerSocket = test;
mmServerSocket.connect();
String message = Double.toString(value);
byte[] send = message.getBytes();
btoutput = mmServerSocket.getOutputStream();
btoutput.write(send);
btoutput.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
};
}
I am not sure you should creating and connecting the bluetooth socket in the broadcast receiver. I do the bluetooth connection management in the onResume() of the activity.
Also I use a thread to manage getting data from the serial data connection between the arduino and the device, it is spawned off and runs continuously in the background. There is a write method to send data out that i call from the activity
/* Call this from the main activity to send data to the remote device */
public void write(String message) {
System.out.println("...Data to send: " + message + "...");
byte[] msgBuffer = message.getBytes();
try {
mmOutStream.write(msgBuffer);
} catch (IOException e) {
System.out.println("...Error data send: " + e.getMessage() + "...");
}
}
then the run() method of the tread takes care of getting data back
See my answer in this thread for an example
Error with receiving xml strings via bluetooth in Android
Good luck!
Check out this page from arduino: http://arduino.cc/en/Reference/Loop
The problem is that it only goes once because it is not in a loop that continues forever until the device is shut off or told otherwise.