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.
Related
I'm going to set a simple socket connection between two android devices using internet.
There are two devices and two android app's , one of them is client app and another is server app.
When the apps run on a device it's all OK, but when the apps run on two devices the client application doesn't connect to server application.
Client app:
btnSend.setOnClickListener(view -> {
String msg = etMessage.getText().toString();
AsyncTask.execute(() -> {
try {
DatagramSocket socket = new DatagramSocket();
InetAddress ip = InetAddress.getByName("100.66.20.245");
int port = 1020;
DatagramPacket packet = new DatagramPacket(
msg.getBytes(), msg.length(), ip, port
);
socket.send(packet);
runOnUiThread(() -> {
Toast.makeText(this, "Message sent", Toast.LENGTH_SHORT).show();
});
} catch (Exception e) {
Log.w(TAG, e.toString());
}
});
});
Server app:
Runnable runnable = () -> {
try {
int port = 1020;
DatagramSocket socket = new DatagramSocket(port);
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer,1024);
runOnUiThread(() -> {
Toast.makeText(this,"Waiting for client",Toast.LENGTH_SHORT).show();
});
socket.receive(packet);
String msg = new String(packet.getData(),0,packet.getLength());
runOnUiThread(() -> {
Toast.makeText(this, "Client msg : " + msg, Toast.LENGTH_SHORT).show();
});
} catch (Exception e) {
Log.w(TAG, e.toString());
}
};
new Thread(runnable).start();
Are both devices connected to a network? And is the IP address of client application equal to the IP address of the server?
The best solution was the port forwarding with a router.
When you are using a router you can set an ip address to forwarding ports to that ip address.
However if you have a better solution, please post a comment :)
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...
I have the following code to receive UDP packets:
public class AsyncReceiveUdp2 extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... f_url) {
int udp=111;
byte[] packet = new byte[2000];
DatagramPacket dp = new DatagramPacket(packet, packet.length);
DatagramSocket ds = null;
try {
ds = new DatagramSocket(udp);
ds.receive(dp);
//...
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ds != null) {
ds.close();
}
}
return null;
}
}
I send UDP data to computer from Android device.
Computer immediately sends response as UDP packet.
I save information to my log file on SD.
And I see, that my app stays on the line "ds.receive(dp);" and does not run after it.
I've tested on the Android device against a program on computer.
As I understand it is tricky to receive UDP packets on Emulator.
I could not do it.
Redirect does not work for me as it is described here
Another important issue is to receive all packets, that were sent to the device. Lossless. How to modify the code for that?
Please help! Thanks!
put your receive inside a while(true) loop. When you receive a packet call an if (pkg_received){break;}... or whatever you want to do...
The problem is that you are probably only be receiving one package and you are getting timeout before receiving it.
Code edited and not tested
while(true)
{
byte[] message = new byte[60*1024];
DatagramPacket recv_packet = new DatagramPacket(message, message.length);
try {
socket.receive(recv_packet);
} catch (IOException e) {
e.printStackTrace();
}
Log.d("UDP", "S: Receiving...listening on port " + recv_packet.getPort() );
String rec_str;
rec_str=new String(recv_packet.getData)
Log.d("PACKAGE LENGTH",Integer.toString(recv_packet.getLength()));
}
I want to implement service discovery by using the network's broadcast address. I am sniffing packets with WireShark to confirm that my UDP packets are not being sent. The network code is not being run on the UI thread. The DatagramSocket.send call returns with no exception thrown, but nothing is seen by other programs including WireShark. I have verified that the address returned by getWifiBroadcastAddress actually is the broadcast address of my network.
I have verified that the network supports broadcast by writing a C# program, run on another machine, and WireShark is detecting broadcast packets from this program.
Here is my Android Java code:
try {
DatagramSocket socket = new DatagramSocket(Protocol.INQUIRY_PORT);
socket.setBroadcast(true);
InetAddress broadcastAddr = getWifiBroadcastAddress();
byte[] data = new byte[10];
for(int i = 0; i < data.length; i++) {
data[i] = (byte) i;
}
DatagramPacket packet = new DatagramPacket(data, data.length,
broadcastAddr, Protocol.INQUIRY_PORT);
while(true) {
// Loops indefinitely, no errors/exceptions
socket.send(packet);
try {
Thread.sleep(5000);
} catch(InterruptedException ie) {
break;
}
}
} catch(IOException ioe) {
// Not logged
Log.d("Broadcast", "Error sending inquiry.");
}
The getWifiBroadcastAddress() method is as seen here: https://lab.dyne.org/AndroidUDPBroadcast
Does anyone know why this would fail silently? Like I said my C# program running on another box is working just fine, doing the same thing, sending the same data every 5s, and WireShark sees those packets, but nothing from the Android phone.
The following works for me, where I can broadcast a particular string value to a specified port (in your case Protocol.INQUIRY_PORT) on the other end(s), and all of the devices on the local subnet that are monitoring UDP on that port can recognize that string value, and accordingly can respond. I am broadcasting from the main thread, but listening for responses in an async task.
public void sendBroadcast(String messageStr) {
// Hack Prevent crash (sending should be done using an async task)
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
byte[] sendData = messageStr.getBytes();
try {
sendSocket = new DatagramSocket(null);
sendSocket.setReuseAddress(true);
//sendSocket.bind(new InetSocketAddress(Protocol.INQUIRY_PORT));
sendSocket.setBroadcast(true);
//Broadcast to all IP addresses on subnet
try {
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("255.255.255.255"), Protocol.INQUIRY_PORT);
sendSocket.send(sendPacket);
System.out.println(getClass().getName() + ">>> Request packet sent to: 255.255.255.255 (DEFAULT)");
} catch (Exception e) {
}
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.getMessage());
}
}
Following is the corresponding UDP response listener code inside an async task class:
protected String doInBackground(String... params) {
serverIP = "";
try {
//Keep a socket open to listen to all the UDP trafic that is destined for this port
InetAddress myHostAddr = InetAddress.getByName("0.0.0.0");
rcvSocket = new DatagramSocket(null);
rcvSocket.setReuseAddress(true);
rcvSocket.bind(new InetSocketAddress("0.0.0.0",Protocol.INQUIRY_PORT));
rcvSocket.setBroadcast(true);
while (true) {
Log.i("VIS","Ready to receive broadcast packets!");
//Receive a packet
byte[] recvBuf = new byte[15000];
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
rcvSocket.receive(packet);
//Packet received
serverIP = packet.getAddress().getHostAddress();
Log.i("VIS", "Packet received from: " + serverIP);
String data = new String(packet.getData()).trim();
Log.i("VIS", "Packet received; data: " + data);
if (!data.equals("") && !data.equals(myInquiryString)) {
//break while loop and return IP address of server
break;
}
}
} catch (IOException ex) {
Log.i("VIS", "ServerDiscovery" + ex.getMessage());
}
return serverIP;
}
I am trying to connect to a my remote server from my Android device. How do I check if a specific port on my server is open? Eg. how to check if port 80 is open on my server 11.11.11.11?
Currently, I am using InetAddress to ping if the host is reachable but this does not tell me if the port 80 is open.
Current Code
boolean isAvailable = false;
try {
isAvailable = InetAddress.getByName("11.11.11.11").isReachable(2000);
if (isAvailable == true) {
//host is reachable
doSomething();
}
} catch (Exception e) {
}
Create a Socket that will check that the given ip with particular port could be connected or not.
public static boolean isPortOpen(final String ip, final int port, final int timeout) {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
return true;
}
catch(ConnectException ce){
ce.printStackTrace();
return false;
}
catch (Exception ex) {
ex.printStackTrace();
return false;
}
}
Runtime.getRuntime().exec() and pass command to it to get various port entry with pid. Commands are below:
“cat /proc/net/tcp”, “cat /proc/net/tcp6”, “cat /proc/net/udp”, “cat /proc/net/udp6”.
Here is explanation with source code. I have tested it. :
http://kickwe.com/tutorial/android-port-scanner-tutorial/