I have an UDP send and receive which works in my device Samsung Galaxy Ace Plus (S7500) but the same code doesn't work in other devices, for example Samsung Galaxy S4. I don't have any error.
Send :
public class SendThread extends Thread {
byte[] receiveData = new byte[1024];
DatagramSocket serverSocket = null;
public SendThread() {
this.start();
}
public void run() {
DatagramSocket serverSocket = null;
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
try {
serverSocket = new DatagramSocket("MY SOCKET PORT");
InetAddress IP = InetAddress.getByName("MY IP");
String send= "I am Android";
sendData = send.getBytes();
DatagramPacket send = new DatagramPacket(sendData, sendData.length, IP, "MY SEND PORT");
serverSocket.send(send);
serverSocket.close();
} catch (Exception e) {
}
}
}
Receive :
public class ReceiveThread extends Thread {
byte[] receiveData = new byte[1024];
DatagramSocket serverSocket = null;
boolean isActive = true;
public ReceiveThread() {
this.start();
}
public void run() {
DatagramSocket serverSocket = null;
byte[] receiveData = new byte[1024];
while (isActive) {
try {
serverSocket = new DatagramSocket("MY RECEIVE PORT");
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String sentence = new String( receivePacket.getData());
System.out.println("RECEIVED: " + sentence);
serverSocket.close();
} catch (Exception e){
}
}
}
}
This problem ocurred because some devices lock the Datagram receiver because the protocol security implemented by factory.
Your code is not wrong, but you need change the DatagramSocket for MulticastSocket.
For this your need execute some steps:
First, it's needed to add the uses-permission:
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
On AmdroidManifest.xml
Second, it's necessary create a MulticastLock; Without this the MulticastSocket is not work properly;
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
multicastLock = wifi.createMulticastLock("multicastLock");
multicastLock.setReferenceCounted(true);
Thirdy, replace the DatagramSocket by MulticastSocket. Only on receive methods was needed put the code below or similar:
MulticastSocket ms = new MulticastScoket("Your socket port");
ms.joinGroup("Your IP");
It's not needed any modifies to send messages.
I use the multcast ip equals to 239.255.255.255. Attempt to range of multicast ip because the wrong ip will block the method flow correctly.
Finally, before use MulticastSocket it's needed to execute MulticastLock.acquire(), and after use execute MulticastLock.release();
It could be puted on service, and acquire or release MulticastLock on start or stop service.
Related
I need to write a Java program that can catch UDP packets. I wrote a basic UDP Receiver program but I am unsure how to adjust it for this purpose.
import java.io.*;
import java.net.*;
public class BasicReceiver {
public static void main(String[] args) {
int port = args.length == 0 ? 57 : Integer.parseInt(args[0]);
new BasicReceiver().run(port);
}
public void run(int port) {
try {
DatagramSocket serverSocket = new DatagramSocket(port);
byte[] receiveData = new byte[8];
String sendString = "polo";
byte[] sendData = sendString.getBytes("UTF-8");
System.out.printf("Listening on udp:%s:%d%n",
InetAddress.getLocalHost().getHostAddress(), port);
DatagramPacket receivePacket = new DatagramPacket(receiveData,
receiveData.length);
while(true)
{
serverSocket.receive(receivePacket);
String sentence = new String( receivePacket.getData(), 0,
receivePacket.getLength() );
System.out.println("RECEIVED: " + sentence);
// now send acknowledgement packet back to sender
InetAddress IPAddress = receivePacket.getAddress();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length,
IPAddress, receivePacket.getPort());
serverSocket.send(sendPacket);
}
} catch (IOException e) {
System.out.println(e);
}
// should close serverSocket in finally block
}
}
I am not receiving any packets but I can see packets on my Ethernet Port:
WireShark Snapshot
I'm writing an android source(but just java) to communicate with some embedded device which acts as a server.
I am sure that my UDP datagrams are arriving to the device since I can observe the device state changing.
But the problem is that I am failing to get response from the server. Not receiving nothing, but I just get an echo of what I sent. My source is as below.
public void sendSnapShot(View view) {
//send a udp datagram to the server.
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... voids) {
try {
Log.e("Test", "send sendSnapShot onLine");
DatagramSocket clientSocket = new DatagramSocket();
byte[] sendData = new byte[1024];
String sentence = "$SNAPSHOT";
sendData = sentence.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("192.168.5.255"), 9999);
clientSocket.send(sendPacket);
Log.e("Test", "Sent sendSnapShot REQUEST");
} catch (Exception e) {
Log.e("Test", "e", e);
}
return null;
}
}.execute();
}
The above code is about transfering datagram to the server. On the start of the application, the below thread will be started to listen for any datagram sent by the server.
private class ListenerThread implements Runnable {
//listen for incoming datagrams.
#Override
public void run() {
DatagramSocket serverSocket = null;
try {
InetAddress serverAddr = InetAddress.getByName("192.168.5.255");
serverSocket = new DatagramSocket(9999, serverAddr);
while (true) {
try {
byte[] receiveData = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
receivePacket.getLength();
String receivedData = new String(receivePacket.getData(), 0, receivePacket.getLength());
if (!receivedData.startsWith("!HEARTBEAT")) {
Log.e("Test", "Received : " + receivedData);
} else {
Log.e("Test", "Received : HEARTBEAT");
}
} catch (Exception e) {
Log.e("Test", "FROM SERVER ", e);
}
}
} catch (Exception e) {
Log.e("Test", "Exception", e);
}
}
}
The guy who wrote the server code(probably written in c++) says that he is getting response in his test case, so what may I be missing? Is there a possiblity that the above code will ignore any datagram from the server and echo bytes sent from my code?
=============================================================================
I've changed my code according to the answer. I no longer use the listening thread anymore. Here's my code.
public void sendBattery(View view) {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... voids) {
try {
Log.e("Test", "send Battery onLine");
DatagramSocket clientSocket = new DatagramSocket(9999, InetAddress.getByName("0.0.0.0"));
byte[] sendData = new byte[1024];
byte[] receivedata = new byte[1024];
String sentence = "$S0B255";
DatagramPacket receivePacket = new DatagramPacket(receivedata, receivedata.length);
sendData = sentence.getBytes();
String receivedData = " ";
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("192.168.5.1"), 9999);
clientSocket.send(sendPacket);
do{
clientSocket.receive(receivePacket);
receivedData = new String(receivePacket.getData(), 0, receivePacket.getLength());
Log.e("Test", receivedData + ", IP CHECK Sender: : " + receivePacket.getAddress().toString() + ", port : "+ receivePacket.getPort());
}while(true);
// Log.e("Test", "Sent BATTERY REQUEST COMPL");
} catch (Exception e) {
Log.e("Test", "e", e);
}
return null;
}
}.execute();
}
According to the heartbeat byte(making it to a string will make it "!HEARTBEAT") i'm receiving, the sender is 192.168.5.1. But still, I only get heartbeat bytes only. What shall I be missing?
You are receiving your own datagrams, because you are broadcasting (to 192.168.5.255). You should use the device's actual IP address.
You should not create a new datagram socket per send. (You are never closing that socket, so you are also leaking sockets.)
You should send the datagrams from the same socket you are receiving on. The device will (should) reply to the IP:port the request came from, and at present that's different every time, and you're losing the sending socket that's bound to that port, and the sending IP:port isn't the IP:port you're listening on, so you don't hear it.
You should not bind your listening socket to a specific IP address, and certainly not to a broadcast address. I'm surprised it works.
What EJP was saying was right about everything.
The fixed code above(the most below code snippet) which included tips from him will work, without having to receive any broadcast by myself.
I thought the issue was unresolved since I still didn't get any response from the device, but it was the device(not made by me) which was malfunctioning. The above code will work good.
I'm trying to communicate a Java program with a C# one but it's not working.
The code is really basic, here it is:
This is the Java client
static InetAddress ip;
static int port = 10000;
public static void main(String args[]) {
try {
ip = InetAddress.getByName("127.0.0.1");
DatagramSocket socket = new DatagramSocket(port, ip);
byte[] sendData = new byte[1024];
sendData = "Hola".getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, ip, port);
socket.send(sendPacket);
socket.close();
} catch (Exception e) {
}
}
And here it is the C# server
static UdpClient client;
static IPEndPoint sender;
void Start () {
byte[] data = new byte[1024];
string ip = "127.0.0.1";
int port = 10000;
client = new UdpClient(ip, port);
sender = new IPEndPoint(IPAddress.Parse(ip), port);
client.BeginReceive (new AsyncCallback(recibir), sender);
}
static void recibir(IAsyncResult res){
byte[] bResp = client.EndReceive(res, ref sender);
//Convert the data to a string
string mes = Encoding.UTF8.GetString(bResp);
//Display the string
Debug.Log(mes);
}
The c# server is a Unity file, I mean, I execute it from Unity, so Start is the first method called.
I would like them to communicate through port 10000 (or any ohter one) in my computer, java's main and c#'s start seem to be executed but the callback is never called.
Any ideas of why it isn't working? Thank you all.
BeginReceive() is non-blocking. Your program terminates before it can receive anything. Either use Receive() or put a busy-waiting-loop at the end of the server code.
I've solved it, in the Java client new DatagramSocket() must be called without any argument, and in the c# server new UdpClient(port); must be called only with the port.
Is it possible to use a single DatagramSocket to send and receive packets in a single Java application? I have been attempting to do this using threads but have had not luck. Every socket tutorial I find online uses separate client and server classes to send data. However, in my case, I want the client and server to reside in a single application. Below is my attempt:
public class Main implements Runnable {
// global variables
static DatagramSocket sock;
String globalAddress = "148.61.112.104";
int portNumber = 9876;
byte[] receiveData = new byte[1024];
public static void main(String[] args) throws IOException {
sock = new DatagramSocket();
(new Thread(new Main())).start();
// send data
while (true) {
InetAddress IPAddress = InetAddress.getByName("127.0.0.1");
int port = 9876;
int length = 1024;
byte [] sendData = new byte[1024];
String message = "hello";
sendData = message.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length,
IPAddress, port);
sock.send(sendPacket);
}
}
public void run() {
//get incoming data
while (true) {
byte[] sendData = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(receiveData,
receiveData.length);
receivePacket.setPort(portNumber);
try {
sock.receive(receivePacket);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String sentence = new String(receivePacket.getData());
System.out.println("RECEIVED: " + sentence);
}
}
}
As you can see I am sending data in a loop on the main thread and receiving data on the loop in the runnable thread. The main thread should continuously send "hello" to the receiver and output the message. However, no output is given?
Am I on the right track here? Is using threads the best way to do this? Is this even possible? And if so is there a better solution?
my android device is connected to my home-wireless-network. Also a special UDP-device is connected to it. My android app successfully can send commands to the UDP-device. But if I open a socket it does not receive data. Can you see what is wrong? I know the ip of the UDP-device from the iphone-APP which is working
Here is how the app send commands:
public static final String SERVERIP = "192.168.2.114";
public static final int PORT = 44444;
public void run() {
try {
serverAddr = InetAddress.getByName(SERVERIP);
DatagramSocket socket = new DatagramSocket();
byte[] buf = message.toByteArray();
DatagramPacket packet = new DatagramPacket(buf, buf.length, serverAddr, PORT);
socket.send(packet);
socket.close();
} catch (Exception e) {
Log.e("UDP", "Sender/Client: Error", e);
}
}
Whereas I have two approaches for receiving data:
public static final String SERVERIP = "192.168.2.114";
public static final int SERVERPORT = 44445;
private InetAddress serverAddr;
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(SERVERIP);
DatagramSocket socket = new DatagramSocket(SERVERPORT, serverAddr);
byte[] buf = new byte[65213];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
} catch (Exception e) {
Log.e("UDP", "Receiver: Error", e);
}
try {
serverAddr = InetAddress.getByName(SERVERIP);
DatagramChannel channel = DatagramChannel.open();
DatagramSocket socket = channel.socket();
byte[] buf = new byte[65213];
DatagramPacket packet = new DatagramPacket(buf, buf.length, serverAddr, SERVERPORT);
socket.receive(packet);
socket.close();
} catch (Exception e) {
Log.e("UDP", "Sender/Client: Error", e);
}
}
The approach in the first try block leads to an exception:
java.net.BindException: Cannot assign requested address
at org.apache.harmony.luni.platform.OSNetworkSystem.bind(Native Method)
at dalvik.system.BlockGuard$WrappedNetworkSystem.bind(BlockGuard.java:268)
at org.apache.harmony.luni.net.PlainDatagramSocketImpl.bind(PlainDatagramSocketImpl.java:81)
at java.net.DatagramSocket.createSocket(DatagramSocket.java:193)
at java.net.DatagramSocket.<init>(DatagramSocket.java:95)
at de.myappname.connection.Receiver.run(Receiver.java:29)
at java.lang.Thread.run(Thread.java:1019)
The second approach just blocks the thread by socket.receive(packet) which does not receive data. From the iphone and specification I know the device sends data via UDP 44445 over WLAN. Any suggestions what is wrong?
Thank you!
UDP port 44445 is used by eMule protocol. Do you have any other eMule clients active on your device?
Update:
The problem seems to be the address you bind to - it must be an address on the localhost, i.e. IP address of your device, not remote device. See DatagramSocket(port, InetAddress) constructor.
I guess you need to put the receive() function inside a while loop since you current code looks like it receives message only once; it doesn't guarantee that it will contain any valid data.