How to programmatically get a public IP address? - android

I didn't find the right solution. The below code gives me local IP address (if I connected to Wifi, it gives IP address like 192.168.0.x), but I want public IP address (same as if I search in google " what is my IP ")
public static String getLocalIpAddress() {
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.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
return inetAddress.getHostAddress();
}
}
}
} catch (SocketException ex) {
ex.printStackTrace();
}
return null;
}
OR
WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
String ip = Formatter.formatIpAddress(wm.getConnectionInfo().getIpAddress());
Can anyone help? Thanks!

Step #1: Create a Web service that returns the requester's IP address
Step #2: Call that Web service from your app.
A device does not know its public IP address (unless that device was seriously misconfigured).

You may use the WS https://api.whatismyip.com/ip.php from whatismyip.com : This would output only your IP address in the simple text. (No input required, output is optional)
You must be a Gold Level Member to access the API
Updated Answer
You can make use of the web service from ipify.org
Read through the documentation here
Use https://api.ipify.org/?format=json WS to get device public IP address. This would output your IP address in JSON format.
You should use ipify because:
You can use it without limit (even if you're doing millions of requests per minute).
It's always online and available, and its infrastructure is powered by Heroku, which means that regardless of whether the server running the API dies, or if there's an enormous tornado which destroys half of the east coast, ipify will still be running!
It works flawlessly with both IPv4 and IPv6 addresses, so no matter what sort of technology you're using, there won't be issues.
....................
....................

I found this simple solution:
public String getExternalIpAddress() throws Exception {
URL whatismyip = new URL("http://checkip.amazonaws.com");
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(
whatismyip.openStream()));
String ip = in.readLine();
return ip;
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Remember that this must be run on a separate thread.

You can do this with a simple thread.
you need to create a function in Activity.class file, and need to request a url that will give your public IP in text form: "https://api.ipify.org/. Click to open.
Add this function call in your onCreate() function.
getPublicIP();
Add this function in your MainActivity.class.
private void getPublicIP() {
new Thread(new Runnable(){
public void run(){
//TextView t; //to show the result, please declare and find it inside onCreate()
try {
// Create a URL for the desired page
URL url = new URL("https://api.ipify.org/"); //My text file location
//First open the connection
HttpURLConnection conn=(HttpURLConnection) url.openConnection();
conn.setConnectTimeout(60000); // timing out in a minute
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
//t=(TextView)findViewById(R.id.TextView1); // ideally do this in onCreate()
String str;
while ((str = in.readLine()) != null) {
urls.add(str);
}
in.close();
} catch (Exception e) {
Log.d("MyTag",e.toString());
}
//since we are in background thread, to post results we have to go back to ui thread. do the following for that
PermissionsActivity.this.runOnUiThread(new Runnable(){
public void run(){
try {
Toast.makeText(PermissionsActivity.this, "Public IP:"+urls.get(0), Toast.LENGTH_SHORT).show();
}
catch (Exception e){
Toast.makeText(PermissionsActivity.this, "TurnOn wiffi to get public ip", Toast.LENGTH_SHORT).show();
}
}
});
}
}).start();
}

Make a call to a server like https://whatismyipaddress.com or http://howtofindmyipaddress.com/.
If you have the page source then parse the ip address out.
There are other servers who only return your ip address. Not a whole html page as above two. But i forgot which one...

Related

Android, accessing device IP address using "Inet4Address.getLocalHost().getHostAddress();" throws exception

so I have an app that is running and on startup, I would like to be able to Get the IP address and display it as a String. I have been using the code below.
String ipAddress = "";
try{
ipAddress = Inet4Address.getLocalHost().getHostAddress();
}
catch(Exception e){
ipAddress = "IP address Cant be used";
}
every time this is run it will return "IP address Cant be used" so it's throwing an error.
If you are looking to get your public facing IP check out this answer. In short you cannot get your public facing IP because the Network Address Transation does not happen in your Kernel, i.e you dont assign your IP to yourself rather it will be given to you thanks to NAT and DHCP. The following code makes a request to amazons's aws IP API, to retrieve your IP
public static String getIp() throws Exception {
URL whatismyip = new URL("http://checkip.amazonaws.com");
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(
whatismyip.openStream()));
String ip = in.readLine();
return ip;
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

What will be the correct IP address if I want to establish socket connection between pc and Android emulator?

I am trying to use pc as server and Android emulator as client.I want to send a message from server to client.Here's the code:
server:
import java.net.*;
import java.io.*;
public class SimpleServer {
public static void main(String[] args)
throws IOException
{
ServerSocket ss = new ServerSocket(30000);
while(true) {
Socket s = ss.accept();
OutputStream os = s.getOutputStream();
os.write("Hello World!\n".getBytes("utf-8"));
os.close();
s.close();
}
}
}
Client:
public class MainActivity extends AppCompatActivity {
EditText text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (EditText)findViewById(R.id.messg);
new Thread() {
#Override
public void run() {
try {
// What ip address should be chosen here?
Socket socket = new Socket("xxx.xxx.xxx.xxx",30000);
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = br.readLine();
text.setText(line);
br.close();
socket.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
I have test the code of server and client on the same computer using localhost:127.0.0.1 and it works.However, I can't figure out if the client is the emulator launched by genymotion on the same computer, what will be the correct IP address for the client socket to connect?
I am using wifi and I have tried IP address of wlan0 (found by ifconfig),127.0.0.1, and the public IP address of my computer (found by Google), but the client emulator doesn't display the message from server.
If you want to refer to the computer which is running the Android simulator, use the IP address 10.0.2.2 instead. You can read more about it here
Have you tried the local area network IP address of the computer? In your ifconfig you must get something line
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
...
inet 192.168.43.238
So use 192.168.43.238

can't ping the same IP twice

I have written this code for pinging class C IP addresses on port 6789, the thread starts when I click on a button called PING. It will retrieve all IP addresses that has the port 6789 open. But what I need is to refresh (re-ping) every, let's say 5 seconds, and add IPs recently joined if exist and omit ones that leave the port. Unfortunately another issue appears. When I started the application the first iteration of the while (true) works perfectly, and it adds any IP that had the port 6789 open to the ArrayList ips_List and then display it on the ListView, and when another device joins the port, my phone will add it to the ips_List also. BUT in the second iteration after the Thread sleeps 5 seconds and then begins to re-ping the IPs from (x.x.x.1 - x.x.x.254) to see if another IP had joined the port when pinging to an IP previously pinged, the Socket will throw IOException (as written in the code).
Why is that happening?
Thread pingo = new Thread(new Runnable() {
public void run() {
while (true) {
if (readableNetmask.equals("255.255.255.0")) {
for (int i = 2; i <= 25; i++) {
String ip_address = readableIPAddress;
String oct1 = "", oct2 = "", oct3 = "", oct4 = "";
StringTokenizer stok = new StringTokenizer(
ip_address, ".");
while (stok.hasMoreTokens()) {
oct1 = stok.nextToken();
oct2 = stok.nextToken();
oct3 = stok.nextToken();
oct4 = stok.nextToken();
}
to_ping_ip = oct1 + "." + oct2 + "." + oct3
+ "." + String.valueOf(i);
if (pingAddress(to_ping_ip, 6789)) {
ips_List.add(to_ping_ip);
}
}
}
// delay 10 seconds, then re-ping
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
break;
}
handler.post(new UpdateIPListViewRunnable());
}
}
});
pingo.start();
PingAddress() function:
public boolean pingAddress(String ip, int port) {
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(ip, port), 200);
socket.close();
} catch (IOException e) {
return false;
}
return true;
}
List where addresses appear:
static public class UpdateIPListViewRunnable implements Runnable {
public void run() {
arrayAdapter.clear();
for (int i = 0; i < ips_List.size(); i++) {
arrayAdapter.add(ips_List.get(i));
arrayAdapter.notifyDataSetChanged();
}
ips_List.clear();
}
}
Your problem is likely in your atypical usage of the word "ping". Traditionally, this refers to sending an ICMP echo request, which does not involve connection state, but is also often not allowed to ordinary user IDs such as your application will run under.
You appear to be using a stateful TCP connection instead, and may be running into difficulty in if your server is not tuned to be able to accept rapid reconnects. So you may want to try testing your server using some other client. You could also have a problem in that TCP will keep trying to get the traffic through, so it won't quickly report network troubles. You may even be ending up with multiple attempts overlapping in time.
Your best solution though would probably be to switch from TCP, which is ill suited to this task, to UDP, which is probably a better match. UDP does not have connection state, and it's also unreliable in that no automatic retries are attempted. You should be able to find a UDB echo server and client type example with a web search.
Thank you #Chris Stratton ... and there is noway that I am changing to protocol to UDP since my project's structure is build over the TCP architecture ... now for my problem I finally FOUND the solution; in my app i have a ServerSocket that is used for pinging ... now considering there are two mobiles with the same app, if PING button clicked then it will ping the other device and and the other device will accept() the connection then close() it. Now on the first mobile it will iterates another time (while(true)) and ping the same device, but that device has the ServerSocket closed so it will returns false. For this is used a recursive thread that when a mobile 1 pings mobile 2, mobile 2 will close the ServerSocket and immediately calls the same thread so the ServerSocket is opened to other pings. I tried it and it worked very well :DDD
[#Experts: any enhancements for this solution!]
Recursive Thread:
static public class ReceivePingThread extends Thread {
public void run() {
try {
ServerSocket joinPort = new ServerSocket(6789, 100);
joinPort.accept();
joinPort.close();
ReceivePingThread ReceivePingThread = new ReceivePingThread();
ReceivePingThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Android Serversocket does not seem to accept connections on emulators

I've been trying to implement a simple socket communication between two Android emulators but just can't seem to get it.
My server:
public void run() {
if (SERVERIP != null) {
try {
serverStatus.setText("My IP: " + SERVERIP);
serverSocket = new ServerSocket(6798);
serverStatus.setText("ServerSocket Created");
}
catch(Exception e) {
e.printStackTrace();
}
try {
while (true) {
serverStatus.setText("waiting for client");
Socket client = serverSocket.accept();
serverStatus.setText("Connected.");
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
String line = in.readLine();
serverStatus.setText(line);
in.close();
client.close();
}
}
catch(Exception e) {
e.printStackTrace();
}
}
else
serverStatus.setText("Couldn't detect internet connection.");
}
My Client:
try {
InetAddress ina = InetAddress.getByName("10.0.2.2");
socket = new Socket(ina, 6789);
}
catch (Exception e) {
e.printStackTrace();
}
try {
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
out.println("Hey Server!");
dispText.setText("sent");
}
catch (Exception e) {
e.printStackTrace();
}
The Client side goes on to display the message "sent" however the Server does not move beyond "waiting for client" (stuck on the blocking accept()).
I've used telnet on my Windows machine to redirect port 6789 to 6798 on the server emulator's console. I've also tried turning off my firewall and the other suggestions posted on the similar questions asked here. Please help as just can't seem to get it and feel like I'm making a very stupid mistake.
Also, can anyone please tell me how it is possible for the Client to move beyond the Socket creation code line if the Server is still stuck on accept(). Or, does it not matter to the client that the Server isn't responding as long as it is listening on the port??
Android emulators are placed behind a virtual firewall/router by design, and cannot see each other, even when they are on the same network. The "Using Network Redirection", as well as "Interconnecting Emulator Instances" part of Google's doc on the emulator explains how to communicate with an emulator instance.
As for your last question. Use the empty constructor for socket, and then use the connect call with a specified timeout.

IP Autodiscovery

I have to network devices:
1. Server (variable IP) that needs to receive a String for further stuff (e.g. Socket 9999). This server has also another socket (e.g. 8888) where it sends it's device name on pairing.
2. Client (variable IP) that does NOT know the IP of the server but wants to send him the string.
On a IP C-network I could iterate through the last octet (0..255) and check if Socket 8888 transmits something. But on A and B networks I have no chance. Is there any other solution for this? (I could iterate through all four octets but that wouldn't be an elegant solution).
Thank you!
The most appropriate way to do it, if they are in the same LAN is:
Client sends a UDP broadcast to a specific port and matching the network class (A,B,C)
Server is listening on this port, receives the broadcast packet and connect or send his IP to the client.
With just two network packets you know the IP address.
--EDITED--
To broadcast:
InetAddress broadcastAddr = SharedFunctions.getNetworkLocalBroadcastAddressdAsInetAddress();
DatagramSocket socket = null;
try {
socket = new DatagramSocket();
socket.setBroadcast(true);
System.arraycopy(BROADCAST_SIGNATURE, 0, buffSend, 0, BROADCAST_SIGNATURE.length);
DatagramPacket packet = new DatagramPacket(buffSend, buffSend.length, broadcastAddr, BROADCAST_PORT);
socket.send(packet);
} catch (Exception e) {
e.printStackTrace();
if(socket != null) try {socket.close();} catch (Exception e1) {}
}
public static InetAddress getNetworkLocalBroadcastAddressdAsInetAddress() throws IOException {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
if(VERSION.SDK_INT < 9) {
if(!intf.getInetAddresses().nextElement().isLoopbackAddress()){
byte[] quads = intf.getInetAddresses().nextElement().getAddress();
quads[0] = (byte)255;
return InetAddress.getByAddress(quads);
}
}else{
if(!intf.isLoopback()){
List<InterfaceAddress> intfaddrs = intf.getInterfaceAddresses();
return intfaddrs.get(0).getBroadcast(); //return first IP address
}
}
}
return null;
}
To receice broadcast:
try {
socketReceiver = new DatagramSocket(BROADCAST_PORT);
socketReceiver.setBroadcast(true);
DatagramPacket packet = new DatagramPacket(buffRecv, buffRecv.length);
while(Thread.currentThread() == cThreadReceiver){
socketReceiver.receive(packet);
//here you receive the packet and can check the sender IP address
}
} catch (Exception e) {
e.printStackTrace();
if(socketReceiver != null) try {socketReceiver.close();} catch (Exception e1) {}
}
You will need to do some editing but should start you in the right track.

Categories

Resources