I"m building a P2P wifi app that requires bidirectional communication between every connected device and a central "host" (I've already addressed the issue of forcing the host onto that device in particular).
I've run through the developer.android tutorials and gotten all I can from those, but my issue at the moment is that I can't seem to get the host's sockets to connect to the P2P client devices properly...
My application for my host side currently displays all of the phones that have "connected" to it (via the p2p connect command) and has the addresses of all of those devices displayed in a list view on screen. These addresses are shown as IPV6(I think) addresses and are usually identical to the device's hard-coded MAC addresses, with one hex pair value changed. Example: Device's MAC is AA:BB:CC:DD:EE:FF and host's address for that device shows as being AA:BB:CC:DD:EE:13 (or similar).
The client side at this point in the workflow is waiting for the server to send it a small packet via port 8000.
However, at this point, when I attempt to connect from the host to any client, it throws the exception "Host could not be resolved..." and lists the device's IP address I'm trying to connect to, which properly matches the expected address that is displayed on screen of the connected devices.
I believe my particular concern revolves around the following line of code:
socket.connect((new InetSocketAddress(device.deviceAddress, 8000)), 5000);
Where device is the WifiP2pDevice that we are trying to connect to. In particular, looking at the InetSocketAddress help page, it expects our "device address" to be in the form of a string of IPV4 or IPV6. Is android's P2P "Device Address" really IPV6? Or am I missing something else completely obvious?
EDIT: I have been properly informed that P2P addresses are not applicable in any shape or form to sockets. The only way P2P sockets can be done this way in Android is:
1. Clients get the IP address of the group owner/server from the Broadcast receiver's P2PInfo object.
2. All of the clients connect to the server's ip using sockets.
3. As the server receives connections, the server can get the ip addresses from the client devices via the socket that is created for each client.
4. Once both parties have each others' IP addresses, proper bidirectional communication can be achieved.
Related
I have been trying to set up an app that allows communication between two devices, a server and a client. I have established the connection and can send messages between the two as long as they are connected to the same source of internet. When I connect the devices to two different sources, I am not able to establish a connection between the two. It works by entering the IP address of the server you want to connect to.
For example, if my server device is connected to my home Wi-Fi and my client device is connected to the same Wi-Fi router, communication works as supposed to. But, when I connect the server to Wi-Fi and my client to cellular data (or different Wi-Fi router), the client is not able to find the server.
From all the searching I've done, I found that it is because my server is bound to my local host. So my question is, How can I make my server reachable from anywhere regardless of what network you are connected to?
I used this tutorial to get my server running:
http://android-er.blogspot.com/2014/02/android-sercerclient-example-server.html
The very first comment is a question that asks why it only works on a local network and someone answered saying you have to set up port forwarding on your router. From what I understand, this will work only if the server device is always connected to the same router. This will not be the case for my app. The server will have a new IP address as the device changes networks. I want this IP address to always be reachable no matter what network the server is connected to.
You will need to create a relay server. This would be set up using a java application on the PC and it would manage virtual "rooms" that then relay the messages to the clients. The computer you run your relay server off of will need port forwarding but the clients will not. Much of the code from that tutorial could be applied to this concept.
See: How to create a java Server that accepts client connections and then build a relay connection for a client pair
If your server is behind a firewall, you will not be able to reach it unless that port is open on the firewall. The only way to avoid this is to have a non-firewalled server.
I followed a chat app tutorial that connects devices using TCP sockets.
For simplicity, I split the app into 2, so that one is the server and the other is the client.
The app works fine when I am using the same wifi network, but it does not when one of my devices jumps into a different network.
This is where I get confused on the concepts.
Because they are different networks, I cannot use the local IP as I have been doing. I did find using the public IP is possible, but I'm still new to coding so am not sure if that's the right method. Should I look into VPS? Or GCM?
Do I need to rewrite my app such that I have 2 clients (that talk to each other) and that they go through the server with a static IP (like a middle man)? But then I get confused because in that case, Client would start first and then talk to Server. But I always thought Server was to start first and wait for an accepting socket??
Not sure if this is the right place to ask these questions, I'm just really confused on the concepts. Thanks!
For socket programming in your apps, the only info you need is IP address and port number. After switching to another network, the only modification to your source code is IP address.
When devices are not in the same local area network, you need routers to locate each other, in theory. If you don't own control to routers, using a public and static IP is the right solution. The app acting as a server should have this static IP and should always be alive, and listen to connections. The app acting as a client starts later and connects to the server with its IP address and the port number you've defined.
Normally when you get access to Internet, you get a public IP from your ISP, and it keeps static if you keep online, in most cases. So just find out the IP address on your server, and connect to this IP address from your client app. If your internet access is gained from a wireless router, you should set up port forwarding on the router, and use the IP address of this router at client.
I am trying to build an embedded device that would be connected to a router.
But I want to be able to know if the device is connected to the router or not using a PC or Mobile.
For example:
How can the PC detect if the google chromecast is connected on the same network or not ?
Do I need to communicate with each IP in the network on a specific port to ask ?
Or do I need to let the embedded device broadcast some information every N seconds ?
Thanks,
In any case you should consider doing a Gratuitous ARP on your embedded device. A gratuitous ARP will announce to all of the devices on your LAN that a new device has joined so they can update their ARP cache.
As far as a PC/Mobile device discovering your embedded device goes, you have a few options:
Option 1
If we can assume that this is a typical flat home network where all of the devices are on a single subnet and there is one gateway router * then you can give your embedded device a unique OUI. If you intend to sell this device you will need to apply for an OUI with the IEEE anyway unless whoever made your chipset supplies it with a MAC address already. Your PC/Mobile app can periodically check its ARP cache for an OUI that matches the unique OUI that you expect.
This will not work if the network is not flat and there are multiple routed subnets or VLANS. Here is a possible scenario: Lets suppose your embedded device connects to a client bridge range extender. If your PC/Mobile app is on the main access point it will never see the MAC address of the embedded device - instead it will see the MAC address of the client bridge. Multiple IPs will be mapped to the client bridge because the client bridge and the client bridge will be switching packets.
*I put the term router in italics because most home routers are merely doing NAT between the WAN/LAN and the LAN side of the router operates like a layer 2 switch.
Option 2
You can do a broadcast ping request, eg. ping xxx.xxx.xxx.255. You'll get a response back from all devices that will accept a broadcast ping request. Just make sure your device does. Then once you have a list of IP addresses you can attempt to open a TCP socket over the arbitrary port of your choosing with all of those IP addresses and then send some unique handshake packet. Your embedded device should be listening over this port and should have some unique reply to this unique packet. Most of the devices on the lan should generally not allow this socket to open, but if they do they should not understand the unique handshake message you send.
Option 3
Send a broadcast UDP datagram with some unique handshake payload. Then your embedded device should reply to the sender of this broadcast UDP packet with some unique response. After this response has been received by your PC/Mobile app you can then open a TCP socket with the IP address the response came from.
I want to have my app able to connect to other devices over the same wifi network and transfer some data, that is phone A and phone B have my app installed and are on the same network. I am able to connect two devices currently with one acting as server and the other being client but this is with a static IP reference to the server device. In the open world this IP will change of course so my problem is how do I get phone A to start up as a server device then have phone B see the server device on the network and connect to it. So the server device would accept this client connection and carry out the needed actions when the connection is made. Is this even possible?
I believe you would have A device listening on port number x, and the client version (device B) looking for that same port number x. This could be wrong.
This is a job for DNS. If you don't have a DNS server available you could invent a discovery protocol in which machine A periodically multicasts the IP & port on which it is listening.
Machine B joins the multicast group. Once machine B knows A's address and port it can open a socket using the code you already have.
I am implementing a mobile chat application, I am using socket connection for implementing p2p connectivity. My chat is working fine with android devices. My issue is I can connect a device in 3g network or with in the same WiFi network but the connection is not working when a device form outside WiFi try to connect a device in the WiFi network. I know it's because of the local IP of the device assigned by the WiFi. How can I root and connect a device in the WiFi?
Sounds more like a router settings issue, than an app issue (meaning that users of your app would need to do this for their own networks as well).
Your wifi router needs to know how to forward communication to your device. So say that your app is connecting on port 1234, then you need to tell your router to forward communication from the outside on port 1234 to the internal IP of your phone in your wifi network.
The phone that is outside of the network should target your network's external IP and port 1234.
Sajan, your issue is not only an IP mapping issue, but also a NAT traversal issue. It is not always possible to punch holes in NATs. And when it is, it must be done with some sophisticated techniques including a super peer located outside of your wifi/lan which will read the translated address from your inside peer.
Unless you are using UDP and the NAT is friendly, it is not possible to send TCP communication directly to the inside peer. In most case, you'll have to check what is possible with the NAT, and if there is something possible, you'll need to perform mapping prediction and tell both peer to attempt com on predicted IP addresses.
That's valid if you don't want you users to have to configure their NATs. And even in that case, such configuration will not always be enough (if there are cascades of NATs, or proxies for example).