Use socket programming for different android device with different network - java

I'm developing one socket app.
Background :
There is two android device.
Both device is on different network (i.e. one is on mobilenetwork and other is on different mobile network or on wifi).
App is working good when on same wifi network.
App is not working on different network.
I've read about port forwarding but this all ended up with router port forwarding, so this has nothing to do with my app, as my app is like to work on different network.
What I've tried:
Use Socket-communication over different networks [ Still unable to find the answer]
I got server ip address using following method and it gives me ip address:
public String getIpAddress() {
String ip = "";
try {
Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
.getNetworkInterfaces();
while (enumNetworkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = enumNetworkInterfaces
.nextElement();
Enumeration<InetAddress> enumInetAddress = networkInterface
.getInetAddresses();
while (enumInetAddress.hasMoreElements()) {
InetAddress inetAddress = enumInetAddress.nextElement();
if (inetAddress.isSiteLocalAddress()) {
ip += "Server running at : "
+ inetAddress.getHostAddress();
}
}
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ip += "Something Wrong! " + e.toString() + "\n";
}
text.setText(ip);
return ip;
}
I'm using static port 8080 [May be this is a problem,please suggest me a option if so].
I'm using this lines at client side to connect but soket object returns null on different network:
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
So,Please suggest me what should i use for communicating over
different real android device with different network [app runs on same
network perfectly]?

https://en.wikipedia.org/wiki/TCP_hole_punching
This technique can be used if you're attached to P2P connectivity.
Otherwise, you can get an online server that is accessible to both clients and it can be used to forward messages between the two. Amazon Web Services is a good option for this, you can get one year free trial with a T2.mini machine with a public IP.
https://aws.amazon.com/

Related

Android can send udp but not receive

I've written a basic udp client server where one android sends message to the server and server relays it to the rest of the clients.
The issue is, the incoming udp messages get to the server and server relays them back but they never reach the rest of the devices.
Whats really amazing is that if I use the server as echo server (i.e relaying only to sender) then everything works. All client and server sockets use same port 2706
Server code
while (true) {
DatagramPacket packetToReceive = new DatagramPacket(new byte[2048], 2048);
try {
listenerSocket.receive(packetToReceive);
InetAddress senderAddress = packetToReceive.getAddress();
relayedBytes += packetToReceive.getLength();
if (!connectedClients.contains(senderAddress)) {
connectedClients.add(senderAddress);
}
for (InetAddress addr : connectedClients) {
// commenting this line will make it an echo server
if (!addr.equals(senderAddress))
{
//The following actually prints the ips of the android
//devices so it knows where to send
System.out.println(senderAddress.getHostAddress().toString() +
" to " + addr.getHostAddress().toString());
byte[] data = packetToReceive.getData();
packetToReceive.setData(data, 0, packetToReceive.getLength());
packetToReceive.setAddress(addr);
listenerSocket.send(packetToReceive);
}
}
} catch (IOException) {
e.printStackTrace();
}
}
android sender logic:
mainSocket=new DatagramSocket(homePort);
//targetAddressString is the public IP of server
target = InetAddress.getByName(targetAddressString);
while (true) {
byte[] data = getdata();
if (data == null)
continue;
DatagramPacket packet = new DatagramPacket(data, data.length, target, targetPort);
mainSocket.send(packet);
}
meanwhile on other thread the reciever just waits with the same udp socket:
while (true) {
Log.d("Player", "Waiting for data");
DatagramPacket packet = new DatagramPacket(new byte[2048], 2048);
try {
mainSocket.receive(packet);
Log.d("Player", "packet received");
//do something with the packet
} catch (IOException e) {
e.printStackTrace();
}
}
It never moves further than waiting for data since it'll block until it receives a packet
Moreover I can also see it in the wifi and Mobile data icons that no data is ever received but data sending is always on and is seen received on the server
**EDIT:- Echo server **
while (true) {
DatagramPacket receivedPacket = new DatagramPacket(new byte[2048], 2048);
try {
listenerSocket.receive(receivedPacket);
InetAddress senderAddress = receivedPacket.getAddress();
if (!connectedClients.contains(senderAddress)) {
connectedClients.add(senderAddress);
}
for (InetAddress addr : connectedClients) {
byte[] data = receivedPacket.getData();
DatagramPacket sendPacket= new DatagramPacket(data, 0, receivedPacket.getLength(), addr, receivedPacket.getPort());
listenerSocket.send(sendPacket);
}
} catch (IOException e) {
// ...
}
}
Basically it should relay the message to every single client who've ever sent any data but somehow it only sends its to its original sender the rest of clients miss it. the code is trolling with me
This is the NAT traversal problem as you have figured out.
Here's a few hints:
The server can be hardcoded to listen on port 2706. But it shouldn't make any assumptions about what source port of received packets are. From your code, it doesn't look like you ever attempt to call setPort. So even if the NAT wasn't mapping your port number differently, I'm not sure how your original code was even getting the any destination port set. But I think you figured this out based on your own answer and your updated code.
Don't hardcode a client port on the client's socket. Choose port "0" (or don't set one) on your socket to let the OS choose the first available port for you. If you have multiple clients behind the same NAT, this behavior will allow for quicker client restarts, multiple devices behind the same NAT, and other nice things.
Holly Molly! I finally figured it out , it was my own fault I wasn't considering my cellphone provider's Nat and was assuming 2706 port in public IP as well.
Turns out actually I was under my cellphone network's NAT and my port 2706 was converted to some hideous port number by the time it reached the server. So I had to consider the port no of the actual packet received rather than the one set on the phone.
In a nutshell it was like this
cellphone (port 2706)-> NAT (port 40234) -> Server (port 40234)
and so I was actually trying to send back data to 2706 instead of 40234 -_-'
Once I start to send back the packets at 40234 (or whatever came with the packet) instead of 2706 , it gracefully followed the path back to my android cellphone and everything was fine.

Android function to return IP address

I'm sending data from android device to localhost database. To do this I need to use my ip address. I can find my ip address by searching 'ipconfig' on the command prompt. I just noticed that my ip address changed slightly even though im using the same wifi connection. The last digit of my ip address changed. This needed a minor change in my code but I was wonder if there was an android function that returned your computers ip address for you so that the code could look like below. Such a function would also help when using other forms of internet connection that would change your ip address.
HttpPost httpPost = new HttpPost("http://" + ipAddressFunction() + "/linker.php");// home wifi
first get your network-interfaces via:
NetworkInterface.getNetworkInterfaces();
then get the IP(s) va:
getInetAddresses()
Here is a function i made to get my Android Device IP.
//Get The Local IP Addresses
private String GetLocalIPAddress(Boolean LoopBack)
{
try
{
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();)
{
NetworkInterface intf = en.nextElement ();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();)
{
InetAddress inetAddress = enumIpAddr.nextElement ();
if(inetAddress.getHostAddress().contains("."))
{
if(inetAddress.isLoopbackAddress() == LoopBack)
{
return inetAddress.getHostAddress();
}
}
}
}
}
catch (Exception e)
{
Log.d(this.getClass().toString(), "Failed Getting Local IP\n\n" + e.getMessage());
}
return null;
}
This function receives a Boolean parameter, if True, it will return the Local Loopback IP (I.E: 127.0.0.1), if False, it will return the normal IP (I.E: 192.168.0.5)
You can try to connect multiple IP, if have the return data is proved to be a computer IP

UDP Hole Punching Java Example

I want to do UDP Hole Punching with two clients with the help of a server with a static IP. The server waits for the two clients on port 7070 and 7071. After that it sends the IP address and port to each other. This part is working fine. But I'm not able to establish a communication between the two clients. I tried the code in different Wifi networks and in 3G mobile network. The client program throws the IO-Exception "No route to host".
The client code is used for both clients. Once executed with port 7070 and once with 7071.
Do you think I've implemented the UDP hole punching concept correctly? Any ideas to make it work?
Here's the server code first, followed by the client code.
Thank you for help.
Code of server:
public class UDPHolePunchingServer {
public static void main(String args[]) throws Exception {
// Waiting for Connection of Client1 on Port 7070
// ////////////////////////////////////////////////
// open serverSocket on Port 7070
DatagramSocket serverSocket1 = new DatagramSocket(7070);
System.out.println("Waiting for Client 1 on Port "
+ serverSocket1.getLocalPort());
// receive Data
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
serverSocket1.receive(receivePacket);
// Get IP-Address and Port of Client1
InetAddress IPAddress1 = receivePacket.getAddress();
int port1 = receivePacket.getPort();
String msgInfoOfClient1 = IPAddress1 + "-" + port1 + "-";
System.out.println("Client1: " + msgInfoOfClient1);
// Waiting for Connection of Client2 on Port 7071
// ////////////////////////////////////////////////
// open serverSocket on Port 7071
DatagramSocket serverSocket2 = new DatagramSocket(7071);
System.out.println("Waiting for Client 2 on Port "
+ serverSocket2.getLocalPort());
// receive Data
receivePacket = new DatagramPacket(new byte[1024], 1024);
serverSocket2.receive(receivePacket);
// GetIP-Address and Port of Client1
InetAddress IPAddress2 = receivePacket.getAddress();
int port2 = receivePacket.getPort();
String msgInfoOfClient2 = IPAddress2 + "-" + port2 + "-";
System.out.println("Client2:" + msgInfoOfClient2);
// Send the Information to the other Client
// /////////////////////////////////////////////////
// Send Information of Client2 to Client1
serverSocket1.send(new DatagramPacket(msgInfoOfClient2.getBytes(),
msgInfoOfClient2.getBytes().length, IPAddress1, port1));
// Send Infos of Client1 to Client2
serverSocket2.send(new DatagramPacket(msgInfoOfClient1.getBytes(),
msgInfoOfClient1.getBytes().length, IPAddress2, port2));
//close Sockets
serverSocket1.close();
serverSocket2.close();
}
Code of client
public class UDPHolePunchingClient {
public static void main(String[] args) throws Exception {
// prepare Socket
DatagramSocket clientSocket = new DatagramSocket();
// prepare Data
byte[] sendData = "Hello".getBytes();
// send Data to Server with fix IP (X.X.X.X)
// Client1 uses port 7070, Client2 uses port 7071
DatagramPacket sendPacket = new DatagramPacket(sendData,
sendData.length, InetAddress.getByName("X.X.X.X"), 7070);
clientSocket.send(sendPacket);
// receive Data ==> Format:"<IP of other Client>-<Port of other Client>"
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
clientSocket.receive(receivePacket);
// Convert Response to IP and Port
String response = new String(receivePacket.getData());
String[] splitResponse = response.split("-");
InetAddress ip = InetAddress.getByName(splitResponse[0].substring(1));
int port = Integer.parseInt(splitResponse[1]);
// output converted Data for check
System.out.println("IP: " + ip + " PORT: " + port);
// close socket and open new socket with SAME localport
int localPort = clientSocket.getLocalPort();
clientSocket.close();
clientSocket = new DatagramSocket(localPort);
// set Timeout for receiving Data
clientSocket.setSoTimeout(1000);
// send 5000 Messages for testing
for (int i = 0; i < 5000; i++) {
// send Message to other client
sendData = ("Datapacket(" + i + ")").getBytes();
sendPacket = new DatagramPacket(sendData, sendData.length, ip, port);
clientSocket.send(sendPacket);
// receive Message from other client
try {
receivePacket.setData(new byte[1024]);
clientSocket.receive(receivePacket);
System.out.println("REC: "
+ new String(receivePacket.getData()));
} catch (Exception e) {
System.out.println("SERVER TIMED OUT");
}
}
// close connection
clientSocket.close();
}
UPDATE
The code is generally working. I've tried it in two different home networks now and it's working. But it isn't working in my 3G or university network. In 3G, I verified that the NAT is mapping the two ports (the client port and by the router assigned port) together again, even after closing and opening the clientSocket. Has anyone an idea why it isn't working then?
UDP hole punching can't be achieved with all types of NAT. There is no universal or reliable way defined for all types of NAT. It is even very difficult for symmetric NAT.
Depending on the NAT behaviour, the port mapping could be different for different devices sending the UDP packets.
Like, If A sends a UDP packet to B, it may get some port like 50000. But if A sends a UDP packet to C, then it may get a different mapping like 50002. So, in your case sending a packet to server may give a client some port but sending a packet to other client may give some other port.
You shall read more about NAT behaviour here:
https://www.rfc-editor.org/rfc/rfc4787
https://www.rfc-editor.org/rfc/rfc5128
UDP hole punching not going through on 3G
For symmetric NAT (3G network connecting to a different mobile network), you need to do Multi-UDP hole punching.
See:
https://drive.google.com/file/d/0B1IimJ20gG0SY2NvaE4wRVVMbG8/view?usp=sharing
http://tools.ietf.org/id/draft-takeda-symmetric-nat-traversal-00.txt
https://www.goto.info.waseda.ac.jp/~wei/file/wei-apan-v10.pdf
http://journals.sfu.ca/apan/index.php/apan/article/view/75/pdf_31
Either that or relay all the data through a TURN server.
You rightly use a rendezvous server to inform each node of the others IP / port based on the UDP connection. However using the public IP and port which is the combination which will is obtained by the connection as you have, means that in scenarios where both hosts exist on the same private network hairpin translation is required by the NAT which is sometimes not supported.
To remedy this you can send the IP and port your node believes itself to have in the message to the server (private ip / port) and include this in the information each node receives on the other. Then attempt a connection on both the public combination (the one you are using) and the one I just mentioned and just use the first one which is successfully established.

Generating a java.netSocket through true address and port

I have a server side application that is going to serve an Android application.
The server side application code has a java.net.ServerSocket in it and when i run below line in command line i can receive reaction on debug mode in Eclipse.
i can find java.net.ServerSocket through true address and true port with line:
nc 0.0.0.0 8650
----EDIT-----
I change a line of code and then try below line
nc 127.0.0.1 8650
----EDIT------
nc still can achieve to have reaction from debug.
I think i can find the socket because i get reaction on Eclipse Debug(Do you think am i right too?).
But to avoid complication, i do not paste server side code here.
Also i have some client code that i try to connect server socket through some address and port:
public static int port = 8650;
public static String httpProtocol = "http://";
public static String performRequest(String str) throws IOException {
InetAddress serverAdr = null;
//EDITED CODE BEGIN
serverAdr=Inet4Address.getLocalHost();
//EDITED CODE END
Socket socket = null;
String response = null;
try {
socket = new Socket(serverAdr,port);
//socket = new Socket(serverAdr,port);//tried both this and above line
BufferedReader in = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()));
out.write(str + "\n");
out.flush();
response = in.readLine();
if (response == null) {
throw new IOException("no response recieved");
}
}catch(Exception e){
e.printStackTrace();
} finally {
if (socket != null) {
socket.close();
}
}
return response;
}
By running above code, a java.net.Socket can not be created,
and i get exception
java.net.ConnectException: failed to connect to localhost/127.0.0.1 (port 8650): connect failed: ECONNREFUSED (Connection refused)
Where might the mistake be?
I can only guess i provide the same address and the same port with nc arguments and hope the java.net.Socket to become generated.
EDIT
Android device is a physical device and connected to host machine with USB.
I am on Ubuntu and i think i do not have a firewall.
I controlled by GUFW and firewall status is off.
You cannot connect to IP address 0.0.0.0 because it is not a valid address. From IP 0.0.0.0 on wikipedia In the Internet Protocol version 4 the address 0.0.0.0 is a non-routable meta-address used to designate an invalid, unknown or non applicable target.
By convention, it can be used to say any interface on localhost.

Print to video Ip-address-from socket

I wish I could create a small application that I print screen the IP address to which the socket is connected.
I'm trying this code:
public void onClick(View v) {
Socket s = new Socket();
String host ="10.10.20.xxxx";
try {
s.connect( new InetSocketAddress( host, 6000 ), 1000 );
InetAddress inetAddress = s.getLocalAddress();
String ip = inetAddress.getHostAddress();
//Now, I would like to have printed out the IP-address
Toast.makeText(getBaseContext(), ip , Toast.LENGTH_SHORT).show();
//But nothing happens
} catch (IOException e) {
e.printStackTrace();
}
}
}
But, I have never seen printed the IP address,
If is necessary I can create a TextView and inside-It put the string ip.
Where am I doing wrong? Thanks!
ulyssessPax:
When you connect/accept to/from a device via TCP sockets, you have the following method from that socket:
socket.getRemoteSocketAddress().toString()
it gives you the remote IP address and the port number where it's connected. For example: 192.168.1.30:6000
socket.getLocalSocketAddress()
it gives you the local IP address and the port number where it has established the connection. For example: 10.0.2.15:54471
Hope it's what you're looking for.

Categories

Resources