hi have at home a rasperry pi running a server java app, connected to de router with the dynamic DNS configured and the in/out communication ports openned.
When i run the android apication client througt 4g everithing is working sucessfull. But when i run the same app connected to the wifi on my local net, where the server are running, the server application looks like death.
Any ideas?
Thanks.
router config
I think the problem is related to your DNS. If you are connected using your wifi, you have to return a local IP-Address. Do you have any chance of configuring your router to return the raspberries local IP-Address for wifi-clients?
Take a look here: link
A simple solution, even if it is not very elegant, is adding the following conditions to your code:
If there is an error connecting to the Dyn DNS, try to connect to the local IP address. (In case you are in the Wifi LAN)
If the local IP address fails, try again your Dyn DNS (in case the user is a real user with real communication problems)
(repeat until the connection is successful)
You can also identify your testing devices (using Settings.Secure.ANDROID_ID, or the IMEI) and use the local IP only for them. Another option is making the URL configurable (with a hidden option for example).
Because of my app can run local, only needs to connect to server for updates. I have block the connection on the server app if the ip from client and server are equals.
At the moment is the best solution to keep the server app running properly.
URL whatismyip = new URL("http://checkip.amazonaws.com");
BufferedReader in = new BufferedReader(new
InputStreamReader(whatismyip.openStream()));
String ip = in.readLine();
try {
SSLServerSocketFactory sslFactory = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
SSLServerSocket ss = (SSLServerSocket) sslFactory.createServerSocket(PORT);
int idSession = 0;
while (true) {
SSLSocket socket = (SSLSocket)ss.accept();
if(socket.getInetAddress().getHostAddress().equals(ip)){
if (socket != null && !socket.isClosed()) {
socket.close();
}
}
((ServidorThread) new ServidorThread(socket, idSession)).start();
idSession++;
}
} catch (IOException ex) {
ex.printStackTrace(System.out);
Logger.getLogger(Servidor.class.getName()).log(Level.SEVERE, null, ex);
}
}
Related
I have a server running in a machine (lets call it MACHINE1). In this file, I have created the start_server = websockets.serve(recv, "serverIP", port). The server is correctly running.
On the other side, I have one android application running working as a client connected to the server (note that both devices are running in the same network)
try {
uri = new URI("ws://" + serverIP + ":port");
} catch (URISyntaxException e) {
e.printStackTrace();
}
mWebSocketClient = new WebSocketClient(uri) {
// my code
}
As I mentioned below, currently the solution is setting serverIP to the IP of MACHINE1 (192.168...), and therefore, if I change the machine to another IP the connection will fail. Is there any way to create a general solution? I tried using localhost but I did not manage to connect to MACHINE1
I have a deployed app that is failing on Android 9. Part of its function is to configure a module over an Access Point network to allow that that module to connect to the users home network.
I have code that detects and connects to the correct WIFI network, but when I attempt to open a socket to the device, it fails - only on Android 9 and only if mobile data is enabled. If I manually disable mobile data on the device everything runs fine.
Socket open() {
Socket sock = new Socket(Proxy.NO_PROXY);
try {
sock.bind(new InetSocketAddress(localIpAddress(), 50000));
} catch (IOException e) {
activity.logContent("Warning: Failed to bind socket : " + e.toString());
}
try {
sock.connect(new InetSocketAddress("192.168.17.1", 5555), (int)5000);
} catch (IOException e) {
// This catch fires when Mobile Data is on.
activity.logContent("Connected to " + activity.mWifiManager.getConnectionInfo().getSSID());
activity.logContent("Couldn't open socket : " + e.toString());
}
return sock;
}
I have tried this with and without the Proxy.NO_PROXY and with and without the bind() call. If the bind call is missing the error implies that the socket is attempting to connect over the cell network. (Note: activity.logContent() is an on-screen log so it is easier to see what is happening when not connected to a debugger).
Any ideas what is going wrong?
After a few days of imprecations I believe I have come to the identification of the problem and therefore to the solution:
The problem occurs due to some changes in the version of android (I presume to be 9.0 even if other changes had occurred on API 21), in particular on the creation of the socket, if the system detects that there is a "better" network (access to internet, high signal, etc, etc) socket creation refers to that network and no longer to the wifi network you would like.
I looked for ways to force the creation of the socket on the wifi network (which is the network I want) and the only way I found is this:
Simply put instead of:
Socket sock = new Socket ();
Do:
ConnectivityManager connectivity = (ConnectivityManager) MyApp.getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity != null)
{
for (Network network : connectivity.getAllNetworks())
{
NetworkInfo networkInfo = connectivity.getNetworkInfo(network);
if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI)
{
if (networkInfo.isConnected())
{
Socket sock = network.getSocketFactory().createSocket();
}
}
}
}
Practically browse the networks present in the device and when you find your active wifi you do nothing but take advantage of this function to get the right socket for sure:
getSocketFactory().createSocket()
Now you have the working socket!
In my case it now works perfectly, if someone finds better solutions, it is welcome, but for now it is the only way I have found to make everything work as in the previous version of android.
In Android 9 there a security config about network: Android security config
Adding your domain in network_security_config might solve your problem. I had this in my network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">119.xxx.xxx.xxx</domain>
</domain-config>
</network-security-config>
I am not sure about the exact reason of why this is happening. However, when you are turning on your mobile data and you are only connected to the internet using your mobile data (considering your wifi is turned off), it gets the IP address from the cellular network which is no more connected in your home network. Hence, this is trivial to expect such timeout scenarios, because, it cannot reach the private IP addresses of your home network starting with 192.168.....
Now my confusion is that even if the mobile data is turned on, and both wifi and mobile data is turned on at the same time, the device should connect to the wifi as a default behavior.
Hence I would like to suggest you check the following.
Android 9 (Pie) introduces special Wifi preference, which prevents connecting to public networks automatically. You might consider checking the settings.
Please check the IP address of your device and check if it has some IP address starting with 192.168..... If not, then definitely, you are getting your IP address from your cellular network and hence it cannot reach your private IP addresses of the home network.
I'm trying to create a SignalR connection between an ASP.NET server (SignalR-Server 3.0.0) and an Android client on a real device. So far I've managed to successfully establish a connection on the same computer using a console application client targeting the IP http://127.0.0.1:5000/.
The server computer and the Android device are both connected to the same LAN (over Wi-Fi), so I tried to set the target IP to be the server computer LAN IP, but an exception is thrown:
java.net.SocketTimeoutException: failed to connect to /192.168.14.167
(port 5000) after 15000ms
Here's the relevant client app, using SignalR Java client:
Platform.loadPlatformComponent(new AndroidPlatformComponent());
String serverUrl = "http://192.168.14.167:5000/signalr";
mHubConnection = new HubConnection(serverUrl);
mHubProxy = mHubConnection.createHubProxy("Hub");
ClientTransport clientTransport = new ServerSentEventsTransport(mHubConnection.getLogger());
SignalRFuture<Void> signalRFuture = mHubConnection.start(clientTransport);
try {
signalRFuture.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return;
}
Am I missing anything/doing anything wrong? Any help will be appreciated.
I want to create a super basic Android App that connects to a python server running on my PC but the python server never gets the connection
my java code:
public class WriteToSocket {
Socket sock;
public void Test() {
try {
this.sock = new Socket("PCName", 9871);
} catch (UnknownHostException e) {
System.out.println("Unknown host: PCName");
System.exit(1);
} catch (IOException e) {
System.out.println("No I/O");
System.exit(1);
}
}
public void Test1(){
try {
this.sock.close();
} catch (IOException e) {
System.out.println("No I/O");
System.exit(1);
}
}
and
public void onClick(View v) {
WriteToSocket a = new WriteToSocket();
a.Test();
}
and my python server is
import socket
sock = socket.socket()
name = "PCName"
port = 9871
sock.bind((name,port))
sock.listen(1)
s,a = sock.accept()
I expected after the button click for the python server to accept the connection (I also tried changing "PCName" to "127.0.0.1")
I've looked around but nothing helped me so far :S
Bind your server socket to one of the IP addresses of your PC which is accessible from your android, and not to 127.0.0.1. Or alternatively bind it to all available interfaces (0.0.0.0).
Then connect from your android to that IP.
E.g. if your PC has IP address 1.2.3.4 then use this IP in both applications.
Use netstat to see if the port is really open on your PC.
Check to see if your android application has the permission to use the internet (specified in the manifest: "USES_INTERNET" or something like that).
Also your python script discards the connection as soon as it is made.
In python change bind address to 0.0.0.0. It will bind for all IPs attached to your machine. Then in android app change to correct IP of your computer.
IP 127.0.0.1 is a loopback and you can't connect to it from outside of the system.
The android phone doesn't know what PCName is, change "PCName" in the python code back to '127.0.0.1', then in the android project put in the local IP address of the server.
This of course assuming that both the phone and the server are on the same local network.
I have a Android application which consumes a webservice on a local network. There's a config screen where the user inform the server IP address, which is running Apache Tomcat.
I'm looking for a way to auto-detect the server based on the current connected wi-fi network.
i.e: The smartphone's IP is 10.1.1.90 and the server IP is 10.1.1.254.
Is there a way to achieve this? I'm thinking on using ping, but I don't know if is a good ideia.
The way I understand it, you need to discover IP of your tomcat server and connect it using your client.
I am assuming , both the server and client is in your control.
One simple way can be to use jGroups Cluster.
You can make your tomcat discoverable
Client can discover it using the name of the cluster you have provided .Refer the JChannel API that Jgroups uses
I simulated it making following server class
public class TomcatServer {
JChannel channel;
private void start() throws Exception {
channel = new JChannel(); // use the default config, udp.xml
channel.connect("TomcatCluster");
}
public static void main(String[] args) throws Exception {
new TomcatServer().start();
}
}
The simulated client class
public class MobileApp extends ReceiverAdapter {
JChannel channel;
private void start() throws Exception {
channel = new JChannel(); // use the default config, udp.xml
channel.setReceiver(this);
channel.connect("TomcatCluster");
channel.close();
}
public static void main(String args[]) throws Exception {
new MobileApp().start();
}
The client will provide you following information
GMS: address=MACHINENAME-47879, cluster=TomcatCluster, physical address=xxxxx:0:xxx:xxxx:xxxx:xxxx:xxx:xxxx:xxxx
** view: [MACHINENAME-31239|1] [MACHINENAME-31239, MACHINENAME-47879]
Where MACHINENAME-47879 is the client machine and port & MACHINENAME-31239 is the tomcat server name and port
Do you want to detect "a tomcat server" or "your tomcat server" ?
I mean, do you have any way to custom your server ? If it's the case, then you could create a very simple test page on your server (say a "Hello" JSP page), which your Android application could look for.
If your Android gets a "Hello" result with a GET request on http://<tomcat_ip>/hello.jsp, then you may assume that the tomcat is online.
If you can't add this test page, then you can test any page which the server is supposed to serve. (even a 404 page which sometimes is not configured well, and shows the tomcat version...)
Tomcat response headers can contain the xpoweredBy field that would advertise Tomcat if enabled. However it is most often disabled due security considerations, and even disabled by default. You however could re-enable it if you need to auto-detect exactly your Tomcat servers. From the other side, indeed, if you can place a web page on your server, you can simply place a marking page with the agreed signature.
If the server IP is unknown, I would propose the following ways to detect the server on the network:
The most straightforward way is to do the breadcast ping (ping -b broadcast_address where breadcast address can be computed here, for instance). All network devices that are configured so would reply, then verify as explained above which one is the server. However pinging broadcast address requires a rooted phone. Also the router may not support.
Your DHCP service (most likely your router) can often be configured to issue always the same IP address for the same MAC address of your server network card.
If the server is a desktop computer or laptop, it could show its address as QR code on display. It is possible for a smartphone to scan the code from the screen, and this is way easier than to enter IP address through the touchscreen. QR code can also include auto-generated password for extra security.
If there is wireless router with the possible login where both server and client are connected, the internal pages of that router often contain the relevant IP addresses. You would need to implement logging into the router and doing some screen scrapping.
I made an Android app which used a local server in the WLAN. I made the terminal (the phone) broadcast it's own IP address, which the server then picked up.
I used MultiCast class on the phone, which added the ip-address of itself to the payload. The server always has a thread in multicast read class that obains the payload of the packet (which is the terminals ip-address). Set the terminal in datagram read state and send the servers ip-address to terminal.
Maybe are better ways, but a great way to get the ip-addresses of unknown terminals in the network.
The way i had resolved this problem is with the use of enumerations.
public 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()) {
return inetAddress.getHostAddress().toString();
}
}
}
} catch (Exception ex) {
}
return null;
}
}