Android UDP Communication - java

I've read many posts on this site on how to receive UDP packets in Android. However, none of this is working for me!
Some basics:
I am testing on my HTC Incredible (Android 2.2) running on 3G (not wifi or anything else). No emulators are involved here.
My code is simple:
My server (running on my PC) is listening for UDP traffic on port 8752.
My Android application opens a DatagramSocket on a random port and sends a packet to my server with this port.
I then save this information (the InetAddress form the received packet and the port found within the packet).
I try to send an UDP packet from my server (again, on my PC) to my Android app (running on my phone) and it does NOT work.
//Server code to initialize the UDP socket (snippet)
public void init() {
datagram_server_socket = new DatagramSocket(port,local_addr);
datagram_server_socket.setSoTimeout(1000);
}
//Snippet of code on the ANDROID APP that sends a packet to the server
public void connect() {
Random r = new Random(System.currentTimeMillis());
int udp_port = 0;
while(true){
try {
udp_port = r.nextInt(1000)+8000;
udp_port = 8000;
comm_skt = new DatagramSocket(udp_port);
Log.i("ServerWrapper", "UDP Listening on port: " + udp_port);
break;
} catch(SocketException e) {
Log.e("ServerWrapper", "Could not bind to port " + udp_port);
}
}
byte[] sdata = new byte[4+tid.length];
i = 0;
sdata[i++] = (byte)(0XFF&(udp_port>>24));
sdata[i++] = (byte)(0XFF&(udp_port>>16));
sdata[i++] = (byte)(0XFF&(udp_port>>8));
sdata[i++] = (byte)(0XFF&(udp_port));
for(byte b: tid){
sdata[i++] = b;
}
DatagramPacket pkt = new DatagramPacket(sdata, sdata.length,
InetAddress.getByName(hostname), port);
comm_skt.send(pkt);
}
//Server's UDP socket listening code
public void serverUDPListener() {
try {
datagram_server_socket.receive(rpkt);
int port = 0;
byte[] rdata = rpkt.getData();
port += rdata[0]<<24;
port += rdata[1]<<16;
port += rdata[2]<<8;
port += (0XFF)&rdata[3];
byte[] tid = new byte[rdata.length];
for(int i = 4; i < rdata.length && rdata[i] > 0; i++) {
tid[i-4] = rdata[i];
}
String thread_id = new String(tid).trim();
for(int i = 0; i < threads.size(); i++) {
ClientThread t = threads.get(i);
if(t.getThreadId().compareTo(thread_id) == 0) {
t.setCommSocket(rpkt, port);
} else {
System.err.println("THREAD ID " + thread_id + " COULD NOT BE FOUND");
}
}
} catch (IOException e) {
if(!(e instanceof SocketException) && !(e instanceof SocketTimeoutException))
log.warning("Error while listening for an UDP Packet.");
}
}
//Corresponds to the setCommSocket call above to save the IP and Port of the incoming UDP packet on the server-end
public void setCommSocket(DatagramPacket pkt, int port) {
comm_ip = pkt.getAddress();
comm_port = pkt.getPort(); //Try the port from the packet?
}
//Sends an UDP packet from the SERVER to the ANDROID APP
public void sendIdle() {
if(comm_ip != null) {
System.err.println("Sent IDLE Packet (" + comm_ip.getHostAddress() + ":" + comm_port + ")");
DatagramPacket spkt = new DatagramPacket(new byte[]{1, ProtocolWrapper.IDLE}, 2, comm_ip, comm_port);
DatagramSocket skt;
try {
skt = new DatagramSocket();
skt.send(spkt);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Right now I've hard coded the port my application uses to 8000. However, what's odd is that EVERYTIME I test my program (and view the IP/Port that is saved on my server), the port the packet came from is always 33081. I have a a thread constantly listening for UDP traffic in my Android App but the code never executes passed the "receive(packet)" part:
public void AndroidUDPListener() {
while(true) {
synchronized(stop) {
if(stop) return;
}
byte[] recieve_data = new byte[64];
DatagramPacket rpkt = new DatagramPacket(recieve_data, recieve_data.length);
try {
if(comm_skt == null)
continue;
comm_skt.receive(rpkt);
byte[] data = rpkt.getData();
switch(data[1]) {
case IDLE:
if(ocl != null) ocl.onCompletion(null);
break;
case KEEP_ALIVE:
break;
}
} catch (Exception e) {
if(!(e instanceof SocketException) && !(e instanceof SocketTimeoutException))
Log.w("ServerWrapper", "Error while listening for an UDP Packet.");
}
}
}
Does anyone see an issue in my code? Or is there some permission/settings I need to set on my application first? I have internet communication enabled.
Example Output (using the port from the packet getPort()):
Android App - Now listening for UDP traffic on port 8000
Android App - Sending packet to server
Server - Received packet from XXXXXX:33081
Server - Sending IDLE packet to XXXXXX:33081
Example Output (using the port from the packet data):
Android App - Now listening for UDP traffic on port 8000
Android App - Sending packet to server
Server - Received packet from XXXXXX:8000
Server - Sending IDLE packet to XXXXXX:8000
The Android App never receives any UDP traffic from using either of the ports.

Sorry for not updating this sooner. The problem was fixed as follows:
I needed to store the DatagramSocket to each thread. The listening socket should also be the socket used to continue communication between the server and client. Here are the bits of updated code.
New socket registration code on thread:
public void setCommSocket(DatagramPacket pkt, int port, DatagramSocket skt)
{
comm_ip = pkt.getAddress();
comm_port = pkt.getPort();
synchronized(comm_pkt) {
comm_pkt = pkt;
}
comm_skt = skt;
}
New Server Listening Code:
public void UDPListen() {
while(true) {
synchronized(stop) {
if(stop)
break;
}
byte[] recieve_data = new byte[64];
DatagramPacket rpkt = new DatagramPacket(recieve_data, recieve_data.length);
try {
datagram_server_socket.receive(rpkt);
int port = 0;
byte[] rdata = rpkt.getData();
port += rdata[0]<<24;
port += rdata[1]<<16;
port += rdata[2]<<8;
port += (0XFF)&rdata[3];
byte[] tid = new byte[rdata.length];
for(int i = 4; i < rdata.length && rdata[i] > 0; i++)
{
tid[i-4] = rdata[i];
}
String thread_id = new String(tid).trim();
for(int i = 0; i < threads.size(); i++) {
ClientThread t = threads.get(i);
if(t.getThreadId().compareTo(thread_id) == 0)
{
t.setCommSocket(rpkt, port, datagram_server_socket);
} else {
System.err.println("THREAD ID " + thread_id + " COULD NOT BE FOUND");
}
}
} catch (IOException e) {
if(!(e instanceof SocketException) && !(e instanceof SocketTimeoutException))
log.warning("Error while listening for an UDP Packet.");
} finally {
for(int i = 0; i < threads.size(); i++) {
ClientThread t = threads.get(i);
t.sendKeepAlive();
}
}
}
}
There was some update to the structure of the server/threads that I will omitt. The important part here is that the socket in which the packet was recieved with was re-used to send data back to the client. Additionally, the actual packet was re-used to send data back:
public void sendIdle() {
if(comm_ip != null) {
synchronized(comm_pkt) {
try {
comm_pkt.setData(new byte[]{1, ProtocolWrapper.IDLE});
comm_skt.send(comm_pkt);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Here is the relevant parts of my wrapper class that shows what each thread was holding:
public class PeerWrapper {
private InetAddress ipaddress;
private Integer port;
private Socket client_socket;
private InetAddress comm_ip;
private DatagramSocket comm_skt;
private DatagramPacket comm_pkt;
private int comm_port;
private byte status;

I had a similar problem. On the Android was two sockets (sending/listening), and on a PC server was again two sockets (sending/listening). The phone would ping the PC's known listening socket with the address of the phone's unknown listening socket, so the PC could reply. Nothing I was doing appeared to be getting the address of the listening socket, as the socket would never receive anything.
This solved my problem: Android: java.net.DatagramSocket.bind: Invalid Argument Exception. Use a channel to create the socket, then binding on null. Now I can use the sending socket on the phone to send a packet containing the port of the listening socket (the IPs are the same) to the PC, obtained with .getLocalPort() The PC reads the byte[], gets the port, and sends packets back to the phones listening port.

android have inbound firewall
you have to use first udop hole punch same sock object with timer

Related

Java Multicast Socket doesn't receive anything on Windows

I need to send and receive in multicast.
This is my Sender:
public static void main(String[] args) {
MulticastSocket socket = null;
try {
socket = new MulticastSocket(3575);
int n = 1;
while (n <= 100) {
byte[] buf = new byte[256];
// non aspetta la richiesta
String dString = new Date().toString();
buf = dString.getBytes();
// invia il messaggio in broadcast
InetAddress group = InetAddress.getByName("230.0.0.1");
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, 3575);
socket.send(packet);
System.out.println ("Broadcasting: "+dString);
Thread.sleep(1000);
n++;
}
socket.close();
}catch(Exception e) { e.printStackTrace(); socket.close();}
}//main
This is my Receiver:
public static void main(String[] args) throws IOException {
MulticastSocket socket = new MulticastSocket(3575);
InetAddress group = InetAddress.getByName("230.0.0.1");
socket.joinGroup(group);
DatagramPacket packet;
for (int i = 0; i < 100; i++) {
byte[] buf = new byte[256];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String received = new String(packet.getData()).trim();
System.out.println("Time: " + received);
}
socket.leaveGroup(group);
socket.close();
}//main
When I run them, the Receiver does not receive anything.
I tried on two different PC ( both with Windows) with AntiVirus and firewall disabled. I also tried with different LAN: my router, my phone hotspot.
It does not work neither on local machine.
How can I solve the problem?
Thanks
I compiled and ran your code on my laptop, with the sender and receiver on the same machine. It works. (Fedora 26 Linux, Java 1.8.0_171)
It seems that the problem is something to do with your networking, not the application code. So, since this not a programming problem, I think you would be better off asking this Question on the ServerFault site ... where they specialize in networking, etcetera.

Multicasting C++ multiple computers on the same LAN

i am working on an assignment for college, i was asked to implement a chat for the LAN of my college.
I am in the process of working with multicast for sending a same message to all registered users on the group. My sender is developed on C++ and the receivers on java. When testing on the same computer the code that i am attaching works fine, sender sends, and receiver receives, but when running client on another computer it does not receive the messages sent.
Server:
int main(){
/** MC socket **/
struct sockaddr_in groupSock;
groupSock.sin_family = AF_INET;
groupSock.sin_addr.s_addr = inet_addr("225.5.4.30");
groupSock.sin_port = htons(54321);
bzero(&(groupSock.sin_zero),8);
int mcsock;
if ((mcsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
perror("Socket MC");
exit(1);
}
int nroM = 0;
while(1)
{
fflush(stdout);
stringstream resp;
resp << "Mensaje multicast: " << nroM << "\n";
cout << resp.str();
/* Send a message to the multicast group specified by the*/
/* groupSock sockaddr structure. */
/*int datalen = 1024;*/
if(sendto(mcsock, resp.str().c_str(), strlen(resp.str().c_str()), 0, (struct sockaddr*)&groupSock, sizeof(groupSock)) < 0)
perror("Sending datagram message error");
nroM++;
sleep(2);
}
close(mcsock);
return 0;
}
Client:
class UDPCliente {
public static void main(String args[]) throws Exception{
InetAddress address = InetAddress.getByName("225.5.4.30");
// Create a buffer of bytes, which will be used to store
// the incoming bytes containing the information from the server.
// Since the message is small here, 256 bytes should be enough.
byte[] buf = new byte[256];
// Create a new Multicast socket (that will allow other sockets/programs
// to join it as well.
try (MulticastSocket clientSocket = new MulticastSocket(54321)){
//Joint the Multicast group.
clientSocket.joinGroup(address);
while (true) {
// Receive the information and print it.
DatagramPacket msgPacket = new DatagramPacket(buf, buf.length);
clientSocket.receive(msgPacket);
String msg = new String(buf, 0, buf.length);
System.out.print(msg);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
Just for extra information, this code with the appropiate imports and includes compile and run.
Thank you!!
Well, apparently i changed to another computer and the code worked. So the firewall had something to do. Im answering so if anybody needs the same problem, the code i attached works perfectly if including and importing the proper libraries!!

connect to another instance of the aplication on the local network in java

I am trying to implement a server/clint java application. Once the server socket is listening on port 3232, I would like to client to automatically browse the network and scan each IP address in the subnet till it finds another instance (server) that is running on port 3232 and then report it's IP address so I can use it in the application to set as the socket connection destination IP address.
I have been suggested to use exec(nmap) to scan the network for the open port but I want to deploy this application on systems where do not have nmap installed.
If I understand correctly, I have to make a for loop to iterate through the host to finally find the right host whose port 3232 is open.
public static ArrayList<InetAddress> checkHosts(int socket, int timeout)
{
ArrayList<InetAddress> al = new ArrayList<InetAddress>();
try
{
byte[] buffer = {1};
DatagramSocket ds = new DatagramSocket(socket);
ds.setSoTimeout(timeout);
DatagramPacket dp;
InetAddress local = InetAddress.getLocalHost();
String subnet = getSubnet(local);
System.out.println(subnet);
for(int i = 1; i <= 255; i++)
{
String host = subnet + i;
try {
ds.send(new DatagramPacket(buffer, 1, InetAddress.getByName(host), 3232));
ds.receive(dp = new DatagramPacket(buffer, 1));
if(dp.getPort() == socket && !dp.getAddress().equals(local))
al.add(dp.getAddress());
} catch(Exception e) {
continue;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return al;
}

Can not get UDP packets

I am trying to get UDP packets ,sent by device via WiFi, on my pc.
The device (kind of card) send every 2 seconds new packet.
The problem is that i do not get the packets on java client i have on my pc.
I see the packets on Wireshark.
Here is my UDP client (java):
public static void main(String args[]) {
try {
int port = 80;
// Create a socket to listen on the port.
DatagramSocket dsocket = new DatagramSocket(port);
dsocket.setSoTimeout(10000);
byte[] buffer = new byte[2048];
// Create a packet to receive data into the buffer
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
// Now loop forever, waiting to receive packets and printing them.
while (true) {
// Wait to receive a datagram
try
{
dsocket.receive(packet);
}
catch (SocketTimeoutException e) {
continue;
}
// Convert the contents to a string, and display them
String msg = new String(buffer, 0, packet.getLength());
System.out.println(packet.getAddress().getHostName() + ": "+ msg);
// Reset the length of the packet before reusing it.
packet.setLength(buffer.length);
}
} catch (Exception e) {
System.err.println(e);
}
}

How can I get the IP address from a multicast socket that is listening to broadcasts?

My server creates a multicast socket which listens for UDP packets. It is receiving packets sent to the broadcast address of the network but I can't get the ip address of the sender:
multisocket.getInetAddress().getHostAddress();
returns
"::"
(I guess its because of null getInetAddress).
How can I get the IP address of the sender?
TIPS: I guess it has to do with the socket not being bound and basically the whole broadcasting because those packets arent sent exclusively to me but to the whole network, but shouldnt they hold the IP address of the sender? Enlighten me please.
Here is the code:
public void run() {
try {
Thread.sleep(5000);
Log.i("SERVERUDP", "Connecting...");
MulticastSocket multisocket = new MulticastSocket(SERVERPORT);
multisocket.setBroadcast(true);
Log.i("SERVERUDP","Server's IP is: " + multisocket.getLocalAddress().getHostAddress());
getLocalIpAddress();
while(true){
byte[] b = new byte[65535];
ByteArrayInputStream b_in = new ByteArrayInputStream(b);
DatagramPacket dgram = new DatagramPacket(b, b.length);
multisocket.receive(dgram); // blocks
ObjectInputStream o_in = new ObjectInputStream(b_in);
Object o = o_in.readObject();
dgram.setLength(b.length);
b_in.reset();
if(o.getClass().getSimpleName().equalsIgnoreCase("Request")){
Request request = (Request)o;
String inetaddress = multisocket.getInetAddress().getHostAddress();
Log.i("SERVERUDP-if", "Sending request to IP: " + inetaddress);
new Thread(new ClientTCP(inetaddress, createRequestFromBroadcast(request))).start();
}else if(o.getClass().getSimpleName().equalsIgnoreCase("String")){
Log.e("SERVERUDP-elseif-string", "WTF received a string: " + (String)o);
}else{
Log.e("SERVERUDP-else", "Unrecognized object of type: " + o.getClass().getSimpleName());
}
o_in.close();
//iteration done only once for testing!
break;
}
multisocket.close();
} catch (Exception e) {
Log.e("SERVERUDP", "Error", e);
}
}
Each packet that you receive might have a different source address. So I'm not sure why you're trying to look at multisocket to figure out the source address.
I have to admit I haven't tried this, but does dgram.getSocketAddress () give you what you want after the multisocket.receive call returns?

Categories