I need to implement the communication among all the devices connected to same WiFi AP. I am using the Google Nearby Connections APIs. I am able to connect to multiple device and communicate. But due to some problem connection getting lost. I have checked the Google documentation, It suggest that "When a device is connected to the host, it may send messages to other client devices."
https://developers.google.com/nearby/connections/android/manage-connections
My doubt is what it mean "it may send messages to other client devices".
If multiple client devices are connected to a Host device, then how a client device can send a message to other client devices?
I never tried this, but it seems you can get the clients endpointId with Nearby.Connections.getLocalEndpointId() on the client devices. Not sure how this helps sending messages to other clients, because the host knows the Client-EndpointIds anyway...
However, as a proof of concept you could do something like this:
In the Host:
String payload = client2EndpointId;
Nearby.Connections.sendReliableMessage(mGoogleApiClient, client1EndpointId, payload);
In the Client1:
#Override
public void onMessageReceived(String endpointId, byte[] payload, boolean isReliable) {
String client2EndpointId = (String) payload;
Nearby.Connections.sendReliableMessage(mGoogleApiClient, client2EndpointId, messageFromClient1ToClient2);
}
And in Client2:
#Override
public void onMessageReceived(String endpointId, byte[] payload, boolean isReliable) {
String messageFromClient1 = (String) payload;
}
The Host sends client2's EndpointId as a message to client1. Client1 then uses this endpointId to send a message to client2.
Connections when using Nearby Connections API are lost when
you or other device gets disconnected to wifi
you and other device are connected to different wifi network (remember you are Nearby Connection which works on local network, if you want to send message via different network use Nearby Message API)
connection is lost even if the application in one of the device is minimised, closed(destroyed) etc
so I think you should log some of these cases.
"it may send messages to other client devices"
developer page mean that a connection status (Accepted, Rejected etc) can be send when the host responds to the connection request.
If multiple client devices are connected to a Host device, then how a
client device can send a message to other client devices?
And, if multiple devices are connected you can send your message (or I should rather say Data) to the host which will send the same data to all the clients connected to it (That's how most of the Host-Client system works).
I hope it helped
Related
I'm trying to get TXT Records from Wifi Direct Printers nearby. So far, I can discover peers and establish a connection. But no luck with TXT Records.
I tried Wifi Direct Service Discovery, and I believe I did everything properly since I compared lots of codes from different resources including sample projects from Google and some open source Wifi Direct Wrappers in GitHub. But I couldn't make it work.
I've also seen some weird issues while trying to achieve that. e.g in some devices, when I start the peer discovery, Wifi Connection started to be turned off and on constantly.
Can someone explain how this actually works ? are DnsSdServiceResponseListener and DnsSdTxtRecordListener made for Android devices rather than Printers ?
I've also tried to listen the MultiCast DNS IP Address (224.0.0.251) with a MulticastSocket after establishing the connection between Android and Wifi Direct Printer, but I couldn't receive any data as well.
Thanks.
I used "DnsSdServiceResponseListener" and "DnsSdTxtRecordListener" successfully in my current project. Both listeners are associated to discovering local services nearby.
To use them properly, you have to do the following:
Implement your listeners
WifiP2pManager.DnsSdServiceResponseListener dnsListener = new WifiP2pManager.DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice device) {
// instanceName is service name and device is the print information
}};
WifiP2pManager.DnsSdTxtRecordListener txtListener = new WifiP2pManager.DnsSdTxtRecordListener() {
#Override
public void onDnsSdTxtRecordAvailable(String fullDomain, Map record, WifiP2pDevice device) {
// here we get the service published information in the record map object
}};
Add the listeners to your WiFiManager object
wifiP2PManagerObj.setDnsSdResponseListeners(mChannel, dnsListener, txtListener);
Add service request
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
wifiP2PManagerObj.addServiceRequest(mChannel,serviceRequest, actionListener);
Finally, discover services
wifiP2PManagerObj.discoverServices(mChannel,actionListener);
After discover services is executed successfully, the listeners should receive the nearby services information.
Hope this helps.
Goodluck.
Update
Wifi direct supported printers don't have any published services by default. To use them you have to connect to them via wifi direct and print normally as its a printer connected to your network. Note that those listeners are meant to capture published services (i.e will not capture anything for any device unless its publishing a service).
I think you will need to run Bonjour discovery once the connection is established. You can see NSD and look for "_ipp._tcp" as the service type. By the way,
for "I've also seen some weird issues while trying to achieve that. e.g in some devices, when I start the peer discovery, Wifi Connection started to be turned off and on constantly." if you're testing on a 7.1 device you might be seeing this issue, for which a patch should be coming soon.
I need to connect 20+ android devices in a client-server network. Each client Android device will be communicating with the server Android device and vice versa. The client devices do not need to communicate with each other.
The server device would need access to internet for a brief period while connected to the clients.
My question is, can Wi-Fi P2P support that many connections reliably? And if yes, how do I go about implementing them?
Or will I have to ensure that all devices are on the same WLAN?
From experience, in a real-world deployment of an Android Wi-Fi Direct application, 20 devices should not be an issue.
Theoretically, the maximum number of devices in a Wi-Fi P2P group, where the GO is an Android device, is 254. The group owner is assigned the IP, 192.168.49.1. Clients are assigned an IP from the range, 192.168.49.2 to 192.168.49.254.
The group owner address is defined by the following in WifiP2pServiceImpl.java:
/* Is chosen as a unique address to avoid conflict with
the ranges defined in Tethering.java */
private static final String SERVER_ADDRESS = "192.168.49.1";
Determining the range for the clients is done as follows:
In WifiP2pServiceImpl.java, the startDhcpServer(String intf) method will start the DHCP server for a given interface - not a surprise. This method is called when the group has started and the device is the group owner.
Taking a closer look at this code, we can see that on the InterfaceConfiguration object, the link address is set to 192.168.49.1 and the prefix length is 24 (prefix length is the number of bits set in a subnet mask, here equivalent to 255.255.255.0) - this implies the answer, but we can dig a little further.
ifcg = mNwService.getInterfaceConfig(intf);
ifcg.setLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress(
SERVER_ADDRESS), 24));
ifcg.setInterfaceUp();
mNwService.setInterfaceConfig(intf, ifcg);
Next, the following commands will restart tethering with the DHCP range specified by the String[], tetheringDhcpRanges. The calls of mNwService (Network Management Service) methods will execute the appropriate netd commands.
ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
String[] tetheringDhcpRanges = cm.getTetheredDhcpRanges();
if (mNwService.isTetheringStarted()) {
if (DBG) logd("Stop existing tethering and restart it");
mNwService.stopTethering();
}
mNwService.tetherInterface(intf);
mNwService.startTethering(tetheringDhcpRanges);
And cm.getTetheredDhcpRanges() is ultimately a reference to the following (ConnectivityManager.getTetheredDhcpRanges() -> ConnectivityService.getTetheredDhcpRanges() -> Tethering.getTetheredDhcpRanges()):
// USB is 192.168.42.1 and 255.255.255.0
// Wifi is 192.168.43.1 and 255.255.255.0
// BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1
// with 255.255.255.0
// P2P is 192.168.49.1 and 255.255.255.0
private String[] mDhcpRange;
private static final String[] DHCP_DEFAULT_RANGE = {
"192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254",
"192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254",
"192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254",
"192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254",
}
and:
mDhcpRange = context.getResources().getStringArray(
com.android.internal.R.array.config_tether_dhcp_range);
if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) {
mDhcpRange = DHCP_DEFAULT_RANGE;
}
in com.android.server.connectivity.Tethering.
Of course, it is possible for the device manufacturer to change this code, so this is also worth considering.
For those planning to deploy applications where there will be many users, a mechanism to allow a more than one device to be GO is required. If data needs to be synchronised between devices, it is simple to simulate "churn" and have GOs only be a GO for a time period before becoming a client to another GO and synchronising any data.
The max number as far as I know is not specified, so you would need to test that out to be certain. Also there could be differences between hardware.
Anyway, the basic implementation would be rather simple. The server would call GreateGroup, so it would be the Groupowner in all cases. And then start locals service advertising. Clients then would simply look for the advertisement and once they see it, they would start connection process to the server. One the server connection is made over Wifi direct you would simply start socket communications from the client to the server (server would have listening socket on all times).
Note that connection would require user to click on the dialog showed when client tries to connect to the group owner. And if you want to get rid of this. Then you could actually use the Accesspoint created by GreateGroup, and add the access point name as well as the password to the advertising. Then your clients could actually use the accesspoint to connect (like to any Wlan accesspoint)
Note though that the Wifi Direct way, would not interfere with Wifi connections, not would it require it. But the accesspoint way would mean that any existing Wifi connection from the client would be disconnected, and the device thinks that the connection made to the server would provide normal internet connectivity.
Remember that devices don't need to be connected to a network to connect to each other. Wi-Fi Direct allows them to connect directly.
Here is a list of Wi-Fi Direct resources that you may find useful: https://groups.google.com/forum/#!topic/wi-fi-direct/uWpuOzHY6y0
I'd recommend following Android's Service Discovery Demo and try implementing it yourself. And here is the source code for the demo.
I'm creating a simple chat program that connects two android devices and they can send simple message
I run the server with Socket on a port (1234 for example)
The problem is from the client i do not know the server IP Address. (and i dont want to enter it manually)
is there a way to find a server that is running on a specific port?or can i run the server on some specific static IP that i can give it to clients?
if not is there another way to communicate with android devices that works on Android 2.2+(don't want to use wifi direct) ?
Thanks in Advance
You can broadcast a udp message from the server specifying your ip in the message. Let the client receive the broadcast and use that msg as the ip address to connect to the socket. (PS : The broadcast receiver must b allowed to receive broadcasts). And you are done!
Assign one SERVER predominantly for getting details such as IP ADDRESS, PORT number,etc.. from all the clients.
Each client when activated will contact the SERVER to register itself first and will get the details(IP ADDRESS,etc) of other device to communicate.
Now they can start waiting for specific device.
On 4.1 you can use Mutlicast DNS for service discovery via the NsdManager (if you are on the same network). If you need this to work over the Internet/3G there is really no good way to do it. You could use Google Cloud Messaging (GCM) to notify clients about the server address, but in any case you will need one 'real' server on a stable address that all participants can reach.
http://developer.android.com/reference/android/net/nsd/NsdManager.html
InetAddress.getLocalHost(); doesnot work for me but ya below code work for me
DhcpInfo dhcp = mWifiManager.getDhcpInfo();
int dhc = dhcp.serverAddress;
String dhcS = ( dhc & 0xFF)+ "."+((dhc >> 8 ) & 0xFF)+"."+((dhc >> 16 ) & 0xFF)+"."+((dhc >> 24 ) & 0xFF);
dhcS contains IP address of server,I used for Wireless connection between multiple devices.
You can use this code
connectionSocket.getRemoteSocketAddress();
No the port can never be fixed with a IP. It is always provided by the user. To know the IP address of the server automatically, you can run this program associated with the chat program.
public class Net {
public Net() throws UnknownHostException {
InetAddress ia = InetAddress.getLocalHost();
System.out.println(ia);
ia = InetAddress.getByName("local host");
System.out.println(ia);
}
public static void main(String args[]) throws UnknownHostException {
Net a = new Net();
}
}
You run can this program by the help of a button which is associated with your chat program.
In my chat application, when I am sending messages/chats to the sender , I am checking the internet connection and the XMPP connection. If both are available, then only I allow the user to send the chat messages.
E.g -
if(connection.IsConnected){
//code to send the message to the sender
}
I am using Openfire Server.
I want to implement a functionality that when the internet is not available and when the user wants to send the message, it should send (i.e the messages should be added in the queue) and should send to the receipient as soon as internet is available again , just as Whats App.
Thanks
Your server is irrelevant in this case if you have no internet/XMPP connection. You just want to buffer the messages in your client and send them once your connection is reestablished.
I will assume you are using Smack or asmack, which means you will want to simply create a connection listener on your connection so that you can send buffered messages when the connection connection is reestablished.
connection.addConnectionListener(new ConnectionListener()
{
:
public void reconnectionSuccessful()
{
resendFromBuffer();
}
});
I'm currently working on a Project in my University which is an Android-App which is supposed to deliver data to a Server.
In order to do that I require a more or less consistent connection to the server via XMPP. It is not really important that the connection is there 100% of the time, but it because the system is supposed to be more or less invisible to the user, user-interaction is supposed to be minimal.
Both the server and the client are xmpp-clients. I use jabber.org as the xmpp server.
I have an Android-Service that is establishing the connection to server and delivers data and this works fine.
Now I tried to make the Service reconnect when connection is lost or is Changed from Wifi to GSM. I wanted to try to make this work with a broadcastreceiver listening to NETWORK_STATE_CHANGED_ACTION. But I did not even get this far.
This is the problem: I tried running the app and then just disabling my wifi. My Phone than automatically switches to GSM and I lose my connection (which I anticipated). But when I try to reconnect manually (e.g. restarting the service) I get errors from the Server. Also my status is still "available". From that moment on it takes way too long until I can connect again.
06-29 18:12:14.888: WARN/System.err(14246): resource-constraint(500)
06-29 18:12:14.890: WARN/System.err(14246): at org.jivesoftware.smack.NonSASLAuthentication.authenticate(NonSASLAuthentication.java:110)
06-29 18:12:14.890: WARN/System.err(14246): at org.jivesoftware.smack.XMPPConnection.login(XMPPConnection.java:404)
06-29 18:12:14.890: WARN/System.err(14246): at org.jivesoftware.smack.XMPPConnection.login(XMPPConnection.java:349)
....
I am actually connected to the xmpp Server but it does not deliver my message:
06-29 18:12:14.882: INFO/System.out(14246): 06:12:14 nachm. RCV (1079704816): <iq type='error' id='7rhk4-70'><error code='500' type='wait'><resource-constraint xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error></iq>
Sometimes I don't get the error, but still no messages are being delivered.
So I think that the server is not allowing me to connect, because I did not disconnect before trying to reconnect. Which I find strange because I thought you could even connect from multiple clients to one account.
I'm posting some code that I think might be relevant:
public void connectToServer() throws XMPPException {
ConnectionConfiguration config = new ConnectionConfiguration(
serverADD, port,
service);
connection = new XMPPConnection(config);
connection.connect();
SASLAuthentication.supportSASLMechanism("PLAIN", 0);
connection.login(user_JID,password);
Presence presence = new Presence(Presence.Type.available);
presence.setStatus("available");
presence.setPriority(24);
presence.setMode(Presence.Mode.available);
connection.sendPacket(presence);
}
this is how I send the messages:
public void sendMessage(String message, String recipient) throws XMPPException {
chat = connection.getChatManager().createChat(recipient, this);
chat.sendMessage(message);
}
Does anyone hava an idea how to solve this? I would even use "dirty" tricks as long as my message gets delivered to the server.
By the way: The senders and the recipients jids are always the same (after initial setup). Just in case anyone thinks that could matter.
Deadlock during Smack disconnect
As Airsource Ltd. mentioned in his comment: Smack is suffering from an deadlock in disconnect() which is loged as SMACK-278. I have made a commit that fixes this in my smack fork.
Android reconnection handling
For the network fallover, have a look at the GTalkSMS receiver. It will issue a ACTION_NETWORK_CHANGED intent, with the boolean extras "available" and "fallover". Your service should "stop" the connection when "available=false" and "fallover=false". How you "stop" the connection is up to you. Sometimes the disconnect() takes very long even with the fix for SMACK-278, this is why we do the disconnect in an thread that will abort after x seconds and then creates a new Connection instance. We reconnect then when the intent with "available=true" is received.
You will find other examples in the GTalkSMS source. I have the app permanently running and it achieves a stable, but not 100% available connection (because of WLAN <-> GSM switches).