android chat between 2 phones using sockets - android

This is a bit long so I'll start with the question: how do I get the ip to link up sockets (not on a private network) on Android phone?
And how can I check if a port is being blocked by the phones ISP?
A bit more info:
I have a program that show users locations on a map and you can click on them and start a chat. I've tested the socket conntion and it was working fine on 2 emulators, but when I tried it on a phone it failed to link up the socket.
Out of time exception on the:
NotificationChat.ChatSocket = new Socket(serverAddr, 5000);
And my best guess is the IP of the server (aka phone 1) is not right, or maybe the port is blocked or in use.
I tried 2 ways to get the phone IP:
public static String getLocalIpAddress() {
try {
Socket socket = new Socket("www.google.com", 80);
Log.i("iptest", socket.getLocalAddress().toString().substring(1));
String ip=socket.getLocalAddress().toString().substring(1);
socket.close();
return ip;
} catch (Exception e) {
Log.i("", e.getMessage());
return "exception in get ip";
}
/*
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()) {
return inetAddress.getHostAddress().toString();
}
}
}
} catch (SocketException ex) {
Log.e("b2264", ex.toString());
}
return null; */
}
IP I got was: 10.227.130.191
Which if i remember right is a class A local IP.
The server side:
while(flag==1)
{
if(ss==null)
{
try {
ss = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
}
try {
Log.d("thread","chatnotifiction befor ss accpect");
Socket NotAvilabale=null;
NotAvilabale = ss.accept();
if(ChatSocket!=null)
{
Log.d("test55","not avilable");
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(NotAvilabale.getOutputStream())),true);
out.println("notav");
NotAvilabale.close();
continue;
}
ChatSocket=NotAvilabale;
Log.d("thread","chatnotifiction after ss accpect");
CharSequence contentText = "someone wants to talk to you";
PendingIntent contentIntent = PendingIntent.getActivity(this, 1, notificationIntent, 2);
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
mNotificationManager.notify(NOTIFI_ID, notification);
} catch (IOException e) {
Log.d("chat notifi io exception","chat notifi io exception ");
e.printStackTrace();
}catch (Exception e) {
Log.d("chat notifi Exception 2","chat notifi Exception 2 ");
// TODO: handle exception
}
}
I do not have much experience with sockets. This is the first time I am using them. I hope one of you has a bit more experience and can help me out.
Thanks in advance (sorry for the crape english).

So while I don't know much about how the cell infrastructures work, I can only imagine that it is similar to any ISP.
So imagine you are a large carrier with millions of clients. You can't give them all each their own reserved public IPs, that would be costly and inefficient. But you do have to give them IPs in order to send data to them. So you basically carve up your network into multiple segments. Each segment has complete network of private ips. Since most connections on phones are not peer to peer it would be safe to assume that all outbound traffic goes through a gateway or a set of gateways until it reaches a public gateway that will relay the message out to which ever public host is beng request. Whatever that gateway's IP is though, is probably what your server (and any server on the internet) would see as the client ip (which is probably not the same as the reported IP by the client). With all the devices acting this way, it would also be safe to assume that you can't just make a connection to 10.227.130.191 from a routable IP within the same network unless it has a port open, which in this case would probably mean running your software. I think physical proximity of phones may come into play on some level deciding as to which private segments two different phones get put it. However in most cases, it is not predictable enough to be able to say that Phone A at Lat1,Lng1 IP 10.127.x.x can talk to Phone B at Lat1,Lng1 IP 10.127.x.y simply because they do not have enough information to know if they are on the same physical segment of the network.
So unless you are on a wifi AP, it would be really really hard to allow a direct connections between the phones simply because the probability of them being on the same routable network would be very low.

Related

Can't connect to Android devices when using Network Service Discovery through Wi-Fi P2P

everyone!
I'm developing an Android app that allows to chat with nearby devices that have installed this app. In order to accomplish this, I'm using the Wi-Fi P2P API and Network Service Discovery to search for such nearby devices.
I've written the code for searching the nearby devices in a thread started by a Service. When a device is detected, the Service sends it (through a broadcast intent) to an Activity which displays the devices detected so far.
The detected devices are added to a recyclerView and, when the user presses one of them, a connection must be established to such device.
The Wi-Fi Direct connection gets established successfully (that is, the WifiP2pManager.connect() method succeeds) and the WIFI_P2P_CONNECTION_CHANGED_ACTION is caught.
In the broadcast receiver, when such broadcast intent is caught, the following code is executed:
NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if (networkInfo.isConnected()) {
mManager.requestConnectionInfo(mChannel, connectionInfoListener); }
With the requestConnectionInfo() method I can obtain more information about the connection, such as the IP address of the device I'm trying to connect to.
To obtain such information, I provide an implementation of WifiP2pManager.ConnectionInfoListener to that method, which is denoted by the connectionInfoListener variable.
This is the code of my implementation of WifiP2pManager.ConnectionInfoListener:
private WifiP2pManager.ConnectionInfoListener connectionInfoListener = new WifiP2pManager.ConnectionInfoListener() {
#Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
InetAddress deviceIP = info.groupOwnerAddress;
int port = servicesConnectionInfo.get(device);
ConnectThread connectThread = new ConnectThread(deviceIP, port, device);
connectThread.start();
"device" is an instance variable of my implementation of BroadcastReceiver which is not important right now. What is important, instead, is the ConnectThread thread. That's the thread that handles the code necessary to connect the socket between the two devices. When I try to connect to a detected device, ConnectThread, in its run() method, creates a new instance of ChatConnection passing the IP address and the port number previously obtained to this constructor:
public ChatConnection(InetAddress srvAddress, int srvPort, String macAddress) throws IOException {
...
connSocket = new Socket(srvAddress, srvPort);
...
}
And here is where the problem occurs. When I test my app on my physical device, all I get is this exception:
W/System.err: java.net.ConnectException: failed to connect to /192.168.49.1 (port 6770): connect failed: ECONNREFUSED (Connection refused)
Of course, I installed my app on a second physical device too, which gets successfully detected and a Wi-Fi Direct connection gets successfully established. But, when comes to this line of code:
connSocket = new Socket(srvAddress, srvPort);
that exception is thrown...
I apologize for the length of this question, but I wanted to be the clearest possible.
I really thank you in advance for any help.
EDIT: I forgot to mention the code for initializing the ServerSocket.
The ServerSocket is initialized in a thread that is started as soon as the Wi-Fi is enabled.
That is, when the WifiP2pBroadcastReceiver (an inner class of the app's Service which extends BroadcastReceiver) catches a WIFI_P2P_STATE_CHANGED_ACTION intent, it checks if the Wi-Fi is enabled and, if enabled, it starts the the thread where the ServerSocket is located:
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) {
int statoWiFi = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (statoWiFi == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
mNsdService = new NsdProviderThread();
mNsdService.start();
}
The ServerSocket is initialized in the run() method of NsdProviderThread:
public void run() {
...
try {
server = new ServerSocket(0);
} catch (IOException ex) {
return;
}
...
while (!Thread.currentThread().isInterrupted()) {
Socket clientSocket = null;
try {
clientSocket = server.accept();
} catch (IOException ex) {
break;
}
try {
ChatConnection chatConn = new ChatConnection(clientSocket);
synchronized (connections) {
connections.add(chatConn);
}
} catch (IOException ex) {
continue;
}
}
"server" is an instance variable of NsdProviderThread declared as ServerSocket.
It looks like you just need to use the correct port number on both ends.
You're using zero, which from the documentation means:
A port number of 0 means that the port number is automatically
allocated, typically from an ephemeral port range.
So, when you create your ServerSocket, make sure it is listening on the same port that the other device uses to initiate the connection:
private static final int port = 6770;
//.....
try {
server = new ServerSocket(port);
} catch (IOException ex) {
ex.printStackTrace();
}
again! I've finally managed to get my app working. Here's what I've done:
Hard-code the port number;
When you get the group owner address in the ConnectionInfoListener implementation, make sure if it is the IP address of the device in use. If it is not, connect a client socket to the group owner address; otherwise, make your app wait for an incoming connection;
Initialize the ServerSocket as soon as possible (for example, when the app starts up).
In order to get the device actual IP address after a Wi-Fi Direct connection has been established, I've used this function which I've found in this project (which is derived by the original Android WiFiDirectdemo) in the "Utils" class:
public static String getLocalIPAddress() {
/*
* modified from:
*
* http://thinkandroid.wordpress.com/2010/03/27/incorporating-socket-programming-into-your-applications/
*
* */
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();
String iface = intf.getName();
if(iface.matches(".*" +p2pInt+ ".*")){
if (inetAddress instanceof Inet4Address) { // fix for Galaxy Nexus. IPv4 is easy to use :-)
return getDottedDecimalIP(inetAddress.getAddress());
}
}
}
}
} catch (SocketException ex) {
Log.e("AndroidNetworkAddressFactory", "getLocalIPAddress()", ex);
} catch (NullPointerException ex) {
Log.e("AndroidNetworkAddressFactory", "getLocalIPAddress()", ex);
}
return null;
}
"p2pInt" is a private static String costant declared in the Utils class as:
private final static String p2pInt = "p2p-p2p0"
However, in my app, I've changed the "p2p-p2p0" string in "p2p-wlan0" since it looks like the network interface of my device for Wi-Fi Direct has that (different) name.
I hope this can help any developer who's trying to create an app that uses Wi-Fi Direct connectivity.

Device discovery in local network

I'm currently developing an android app using SDK >= 16 which should be able to discover different android devices (later also iOS devices) in a local area network using the WiFi radio.
My first guess was to use multicast which turned out to be non functional on my Samsung Galaxy S2: packets are only received when sent from the same device.
My second guess is to actively scan the network using a limited IP address range and wait for a proper response. Unfortunately, this implies that the network uses DHCP to address the IP addresses.
None of the above solutions seem to be the perfect solution.
My current solution for my first guess:
public class MulticastReceiver extends AsyncTask<Activity, Integer, String> {
private static final String host = "224.1.1.1";
private static final int port = 5007;
private static final String TAG = "MulticastReceiver";
protected String doInBackground(Activity... activities) {
WifiManager wm = (WifiManager)activities[0].getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock multicastLock = wm.createMulticastLock("mydebuginfo");
multicastLock.acquire();
String message = "Nothing";
if (multicastLock.isHeld()) {
Log.i(TAG, "held multicast lock");
}
try {
InetAddress addr = InetAddress.getByName(host);
MulticastSocket socket = new MulticastSocket(port);
socket.setTimeToLive(4);
socket.setReuseAddress(true);
socket.joinGroup(addr);
byte[] buf = new byte[5];
DatagramPacket recv = new DatagramPacket(buf, buf.length, addr, port);
socket.receive(recv);
message = new String(recv.getData());
socket.leaveGroup(addr);
socket.close();
} catch (Exception e) {
message = "ERROR " + e.toString();
}
multicastLock.release();
return message;
}
}
This code results in blocking on line socket.receive(recv); If I specify a timeout, I get a timeout exception.
Check my answer in very similar question Android Network Discovery Service (ish) before API 14
I do not belive that multicast is not working on Galaxy S2, some time ago when I was coding some network application, I made several test on many devices, some older like G1 but also on S2, S3 and Galaxy Tab 10.
But to be able to use multicast you must enable it programatically.
Have you used this piece of code?
WifiManager wifi = (WifiManager)getSystemService( Context.WIFI_SERVICE );
if(wifi != null){
WifiManager.MulticastLock lock = wifi.createMulticastLock("Log_Tag");
lock.acquire();
}
Check out http://developer.android.com/training/connect-devices-wirelessly/index.html It mentions two ways of finding local services- NSD and wifi direct.

How to get the system ip address after usb tethering of android phone?

I'm developing a mobile application in android.
Here I want to detect the IP address of the computer,system,etc after the usb tethering of the any android phone
I cannot find the solution.
If I put the following code then it takes the only the IP address of phone ,I need IP address of system
The following are code
ArrayList<InetAddress> arrayList=new ArrayList<InetAddress>();
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();
arrayList.add(inetAddress);
inetAddress=null;
}
}
} catch (SocketException ex) {
Log.e("SALMAN", ex.toString());
}
return arrayList;
Please help me to get the system's IP address,If we cannot able to get means so please mention me. Because I'm new to android.
I'm using android 1.6 .
There is server side application in the windows xp system. That application is a windows service which is developed by C# .net.
That windows service listen to some port such like 234,etc.If some data comes to port then it will process the data and send response through that port.
In android the android application is send the data to the windows service via socket.
The android phone is USB tethered to the system in which windows service is running.Then system assume android phone is modem and additional IP address is generated for the system.This ip address is dynamically generated when the android phone is tethered.
For data transfer form mobile to system via socket .I will need to give the ip address of the system (after tethered) in my android coding.
If there is any method in android coding to get this IP address.
All are please give your ideas on regarding this.
Its not possible to find IP address created in PC from android after tethering. There is no API or other way to find it.
If you use InetAddress , it will return 192.168.42.129 - which is a DHCP address created by USB Tethering. It wont help you to communicate.
The other way is to scan the list of IP. USB Tethering will create ip ranging for 192.168.42.1 to 192.168.42.255 . You can write a simple scanner to find which one is active. But it will take some time.
Thanks to 'Swim N Swim' above. I found a code at
Retrieve IP and MAC addresses from /proc/net/arp (Android)
and modified a bit to get first IP having valid mac address. Works great when developing as a single user on your PC with tethered. You may follow above link for further selective IPs based on company name etc.
public static String getUSBThetheredIP() {
BufferedReader bufferedReader = null;
String ips="";
try {
bufferedReader = new BufferedReader(new FileReader("/proc/net/arp"));
String line;
while ((line = bufferedReader.readLine()) != null) {
String[] splitted = line.split(" +");
if (splitted != null && splitted.length >= 4) {
String ip = splitted[0];
String mac = splitted[3];
if (mac.matches("..:..:..:..:..:..")) {
if (mac.matches("00:00:00:00:00:00")) {
//Log.d("DEBUG", "Wrong:" + mac + ":" + ip);
} else {
//Log.d("DEBUG", "Correct:" + mac + ":" + ip);
ips = ip;
break;
}
}
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return ips;
}
Note that each time you tether after untether, you must start your apache or other processes on PC to take new IP effective. THis is what I experienced.

Use TCP in Internet

I'am use TCP for connect my android phone with Windows 7 PC. When I'am send message phone-PC in LAN this system is work, as i`am use this system in Internet she is down because android app send me "time out". Why?
// The host name can either be a machine name, such as "java.sun.com", or a
// textual representation of its IP address
String host = "10.26.144.118";
int port = 20;
try {
Socket socket = new Socket(InetAddress.getByName(host), port);
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
// true for auto flush
writer.println("Hello World");
myView.setText("Send hello world");
} catch (Exception e) {
System.out.println("Error" + e);
myView.setText("Error" + e);
}
You are probably looking for port-forwarding
Your problem is that you mixed up the LAN (local area network) with the WAN (wide area network) aka the internet. Your personal LAN is protected from outside.
You need a static public IP or a DDNS (Dynamic DNS) solution e.g. dyndns. Than you have to forward the traffic from your public IP to you internal Server IP. See also thax's answer.
Than can your smartphone connect to your static public ip or to your DDNS address. Than should your app also work with the mobile network.

Would like to find out how long the network has been connected for

I am using the following function to get the local IP address of the Android device:
/**
* Loops through all network interfaces to find one with a connection
* #return the IP of the connected network device, on error returns null
*/
public String getIPAddress()
{
String strIPaddress = null;
try
{
Enumeration<NetworkInterface> enumNetIF = NetworkInterface.getNetworkInterfaces();
NetworkInterface netIF = null;
//loop whilst there are more interfaces
while(enumNetIF.hasMoreElements())
{
netIF = enumNetIF.nextElement();
for (Enumeration<InetAddress> enumIP = netIF.getInetAddresses(); enumIP.hasMoreElements();)
{
InetAddress inetAddress = enumIP.nextElement();
//check for valid IP, but exclude the loopback address
if(inetAddress.isLoopbackAddress() != true)
{
strIPaddress = inetAddress.getHostAddress();
break;
}
}
}
}
catch (SocketException e)
{
Log.e(TAG, e.getMessage());
}
return strIPaddress;
}
However, I also need to know for how long this IP address has been connected for.
I've searched through the InetAddress structure and couldn't find it:
http://developer.android.com/reference/java/net/InetAddress.html
is there another way to find out for how long the local IP address has existed / connected ?
AFAIK, you would have to watch for connectivity changes (via ConnectivityManager, CONNECTIVITY_ACTION, and your own BroadcastReceiver) and track it yourself.
You'll need to create a background service to handle the monitoring and record when changes are made to the ConnectivityManager.
Note that you'll want to make sure the service starts at boot (triggered by the intent android.intent.action.BOOT_COMPLETED), too; otherwise, it will only keep track of connection changes after the user launches the service.

Categories

Resources