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:
//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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With