Very stuck on this one, so I appreciate any help you can give!
I have two programs, an Android app and a multi-socket Java server. The Android app first establishes an outbound connection to the server (port 21) then accepts in inbound connection from the server (port 1025). For consistency I'll always call the Android app the client and the Java app the host, regardless of the direction the connection is being established in.
The programs work perfectly on a local network, with either my android phone connecting to my local server ip 192.168.1.103 or the emulator on the PC hosting the server connecting to 10.0.2.2.
However when I move outside of my local intranet, I can still establish the android->server connection on port 21 but I time out trying to connect from the server to the phone on port 1025.
A list of things I am accounting for:
Android emulator has port 1025 redirected
Windows (Win 7 server host) firewall is disabled, other known firewalls are disabled
The incoming connection listener is not on the main thread (SDK 2.1 so shouldn't matter)
Router ports 21 and 1025 are being forwarded
A list of tests and their outcomes:
Connecting to server's public ip (router present) from emulator/android phone on local network/android phone on remote network - fails to establish server->phone connection
Removing router and connecting from emulator or remote android phone - fails to establish server->phone connection
Connecting from emulator to 10.0.2.2, router present or not - succeeds
Connecting from android phone on local network to 192.168.1.103 - succeeds
And finally some code, the Servers's output connection attempt (connection is created in the constructor since a sub-thread for this client was already created upon the server's receipt of an inbound connection)
OutputSocketServer(InetAddress inetAddress, int port, int count , LinkedBlockingQueue<Packet> outQueue) {
this.outQueue = outQueue;
SocketAddress sockaddr = new InetSocketAddress(inetAddress,port);
try {
outConnection = new Socket();
System.out.println("Connecting to " + sockaddr.toString());
outConnection.connect(sockaddr, timeout);
System.out.println("Connected to port " + outConnection.getPort() + " of " +outConnection.getInetAddress().toString() + " from local port " + outConnection.getLocalPort());
osw = new ObjectOutputStream(outConnection.getOutputStream());
} catch (IOException e) {
System.out.println("Output Socket Server: Could not establish outbound connection" + e.toString());
e.printStackTrace();
}
}
and the relevant part of the Android Client's connection accept code
public void run() {
try {
System.out.println("Listening for connection on local port " + inSocket.getLocalPort());
this.inConnection = inSocket.accept();
System.out.println("Accepted connection on port " + inConnection.getPort() + " from ip " + inConnection.getInetAddress().toString());
isr = new ObjectInputStream(inConnection.getInputStream());
}
catch (Exception e) {
System.out.println("Inbound Socket Server: " + e.toString());
}
}
The stack trace for the android client just says SocketTimeoutException: operation timed out and for the server ConnectException: connection refused: connect. Prior to that the client's LogCat shows Listening for connection on port 1025 and the server Connecting to /my.ip.he.re:1025
Thanks for any guidance!
Most wireless services assign only non-routable RFC1918 addresses to devices, and route "the internet" through NAT. That means your device can make outbound connections - but you cannot connect to it from the outside (inbound). One reason is the lack of free IPv4 address space.
Since your post mentions Port 21: If you want FTP, use passive mode. In this mode the Android device will make the data connection to the server.
Related
I have a project where I have to build a system where multiples server communicate between each other to respond to clients.
I can make the client communicate with the server but I'm having problems on making the servers start a connection between them.
In the code below you can see that I have a list with the ip's of all the server. For each ip the current server tries to connect with the other server. You can also see that the server wait's for connections, in these case, connections from the other servers.
#Override
public void run() {
// Trying to connect with server
for (String serverIp : servers) {
System.out.println("Trying to connect with " + serverIp);
try {
Socket clientSocket = new Socket(serverIp, this.port);
this.clientPool.submit(new ClientThread(clientSocket, this.streamHandler));
} catch (Exception e) {
System.out.println("Error");
}
System.out.println("Connected with " + serverIp);
}
// Receiving connections from other servers
// In these case we call client to the other server
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("Waiting for clients to connect...");
while (true) {
Socket clientSocket = serverSocket.accept();
this.clientPool.submit(new ClientThread(clientSocket, this.streamHandler));
}
// serverSocket.close();
} catch (IOException e) {
Configuration.printError("Error starting server", e);
}
}
The problem is that the server needs to try to connect with the other servers and wait for connections from the other servers. And after receiving a new connection it needs to stop trying to connect to the correspondent server or if the server have success trying to connect with the other server, it needs to stop receiving new connections from that server.
Any suggestions on how to implement this with sockets?
It seems like you try to do this in steps, first all servers try to connect to the others, but no server have started to accept connections yet. And after the clientSocket has connected to servers, you then start to accept connections. It sounds like this can lead to a deadlock.
You know that each server must accept connections from other servers. You also know that each server need to initiate connections to the other servers.
You must either accept connections and initiated connections in two different threads, or you should use an asynchronous/event driven model and manage an event loop.
And after receiving a new connection it needs to stop trying to connect to the correspondent server or if the server have success trying to connect with the other server, it needs to stop receiving new connections from that server.
Here you want to avoid a race. This is easiest to do if each server wait X time before trying to connect to the other servers. This X should be a random delay from startup. E.g. server A waits 5 seconds before connecting, server B waits 1 second, and server C waits 13 seconds before connecting. But server B and C will not initiated any connections since server A already have established connections to those servers.
I am doing a project for which connection between server and client is required.
I did it by adding TCP sockets.
Here is the code fraction :
Server:
ServerSocket welcomeSocket = new ServerSocket(80);
while(true)
{
Socket connectionSocket = welcomeSocket.accept();
WorkerThread wt = new WorkerThread(connectionSocket, id);
Thread t = new Thread(wt);
t.start();
workerThreadCount++;
}
Client :
Socket skt = new Socket("192.168.0.108", 80); // The IP address is from cmd->ipconfig/all-> IPv4 Address
outToServer = new PrintWriter(skt.getOutputStream(), true);
inFromServer = new BufferedReader(new InputStreamReader(skt.getInputStream()));
It all works when both ends are in same device/under same WiFi.But I don't understand what to do for creating connection over internet.
Please help with clear steps.
Here:
Socket skt = new Socket("192.168.0.108", 80);
That is local address. If you want to have a server that is reachable on the internet, then that server needs to have its global public IP address!
In other words: you have to make sure that the server can be reached from the internet somehow. For example by turning to some service provider that hosts servers that you can then equip with your code!
The whole purpose of 192.168 addresses is to be defined only in a local subnet.
Alternatively, you have to check if your ISP has a service where the ISP assigns an IP address to your connection, and that allows calls from the internet to go to your "place".
Meaning: when you want to receive phone calls, you need a phone that is connected to the phone net!
In order to connect to a socket over WAN, you must port forward that port to your local device. This can be done in your routers' settings.
192.168.0.108 --> That's your local IP-address.
This can be used on your local network without any requirements for port forwarding whatsoever. However, to use it over WAN, execute the following steps:
Step 1: Search for your routers' model number and port forwarding on Google on how-to forward port 80 to your local IP-address. Warning: use a static IP-address on your local device to prevent your IP from changing after a reboot.
Step 2: Go to a website like IP Chicken and find your external IP-address.
You can then connect to your socket using:
Socket skt = new Socket("[EXTERNALIP]", 80);
Please be noticed: unless you have a business network, your external IP-address will probably change from time to time.
I'm trying to build a project where I must pilot an IoT device from smartphone via Wifi.
This device has the SPWF01 Wifi Module integrated, and is configured as an access point (that has no Internet access) with security type WEP. On this access point configuration we also have a TCP Socket Server that intercepts smartphone communications.
On the smartphone side, we have the part which scans and connects to our device's access point(which works, although i get the esclamation point on the wifi icon since it has no Internet access). After we've connected, we start the Client Socket which connects to the server on our IoT device(the ip address of the server socket is actually the gateway of the access point). And here is where the trouble starts, because the client socket won't start. Here is the code:
public void SocketInit(String ip, int port) throws IOException {
InetAddress addr = InetAddress.getByName(ip);
SocketAddress sockaddr = new InetSocketAddress(addr, port);
nsocket = new Socket();
nsocket.setReuseAddress(true);
nsocket.setTcpNoDelay(false);
nsocket.setReceiveBufferSize(700); //Must be less than 730byte witch is the module buffer
nsocket.setSendBufferSize(700);
nsocket.connect(sockaddr, 5000); //5 second connection timeout
}
And here is the exception i get:
java.net.SocketException: socket failed: ENONET (Machine is not on the network)
And I get that error even before reaching nsocket.connect(), precisely on setReuseAddress.
Since the exception I get is ENONET, I thought that it must be because the access point has no internet access so I used the solution proposed here for testing purpose:
adb shell settings put global captive_portal_detection_enabled 0
This is a solution that can't be done programmatically without having root access, but I wanted to test if that was the problem. But although the exclamation mark on the wifi icon had disappeared, the client socket still gave me the same exception error.
Does anybody have a solution for this behaviour? Thank you in advance!
Sometimes the client socket manages to open, with a success rate of 1 out of 20 times. But when it does, i usually get another exception after a couple of messages sent:
java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)
Here is the code I used to connect to the access point from the smartphone:
WifiConfiguration wc=new WifiConfiguration();
wc.SSID= host;
wc.status = WifiConfiguration.Status.ENABLED;
wc.priority = 40;
wc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
wc.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
wc.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
wc.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
wc.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
wc.allowedGroupCiphers.clear();
wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
wc.wepKeys[0] = password;
wc.wepTxKeyIndex = 0;
int netId = mainWifi.addNetwork(wc);
try {
//mainWifi.setWifiEnabled(true);
mainWifi.disconnect();
mainWifi.enableNetwork(netId, true);
mainWifi.reconnect();
startConnectionCheck = true;
System.out.println("enabled network");
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
The access point's security type is WEP. That is because the Wifi module can't implement WPA.
Tests done on Marshmallow.
I am not 100% certain if this issue is the same.
I had to do a project a whileback and used Java sockets.
When doing intial testing, I used the local loopback and used ports on the same computer and multiple threads. Eventually it worked well enough to test between two computers. I found it didn't work between two computers. After turning off all my firewalls and protections etc on the network and getting desperate enough to use direct connection ethernet cables, I figured out the issue.
Sockets cares which gateway you use. The solution was for me to use the gateway rather than the loopback... It is obvious looking back now...
Anyway, it is likely that your mobile gateway, wifi gateway, and local loopback are all different.
Here is an ugly code blurbe that I hope gives direction with very little inspiration...
Socket socket = null;
try {
socket = new Socket(ip, port, InetAddress.getLoopbackAddress(), localServerPort);
}
catch (Exception e) {
}
if (socket == null) {
try {
socket = new Socket(ip, port, InetAddress.getLocalHost(), localServerPort);
}
catch (Exception e) {
}
}
if(socket == null) {
throw new Exception("Neither the loop back nor the host could find this sucker.");
}
I'm developing an application on android studio. I'm trying to open a socket connection.
When the user enters the right IP address, everything works fine, but if the address is not the right IP, the Socket is not connected.
But the problem is that the Socket does not throw an catch Exception, the app is running and now if the user enters the right ip address, the socket is not connected.
My question is why it does not throw an catch Exception if the IP address is not the right IP and how can I make it work?
Here is the code
try {
sockettcp = new Socket(Address, Port);
} catch (Exception e) {
valid = false;
}
Normal way of Socket is that it tries to connect to the given IP on the given Port.
If for some reason the IP is not the right one, the Socket will not throw an err, instead it will "timeout" trying to reconnect every minute or so (Main thread or the GUI thread).
The 4 errors that are Thrown by this type of constructor public Socket(String host, int port) are:
IOException //- if an error occurs during the connection
SocketTimeoutException //- if timeout expires before connecting
IllegalBlockingModeException //- if this socket has an associated channel, and the channel is in non-blocking mode
IllegalArgumentException //- if endpoint is null or is a SocketAddress subclass not supported by this socket
To "Fix" your problem, you can set the timeout to your value (this cannot exceed the platform default)
Socket sck = new Socket();
sck.connect(new InetSocketAddress(ip, port), timeout);
To "Check" if your Socket is connected, you could try this:
Socket.isConnected(); //Returns the connection state of the socket.
Note: Closing a socket doesn't clear its connection state, which means this method will return true for a closed socket (see isClosed()) if it was successfully connected prior to being closed.
See the javadoc for more info about theSocket.
We want to capture the data which comes to the system on port say 7777.
public static void main(String[] args) {
try {
final ServerSocket serverSocket = new ServerSocket(7777);
new Thread("Device Listener") {
public void run() {
try {
System.out.println("Listener Running . . .");
Socket socket = null;
while ((socket = serverSocket.accept()) != null) {
System.out.println("| Incoming : "+ socket.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
};
}.start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
We have a device which sends data to the port 7777, which comes with a native windows application. The windows native application is receiving data which comes from that device. We have to receive that data on port 7777 through our java project.
In the above code,
The java server socket is created but no incoming connections are received from the device.
The java server socket is receiving connections from telnet command.
The data format which is used by the device and the other native application may be different, but atleast it has to be connected from java server socket. is it correct?
how to receive the data which is transmitted to port 7777.
EDIT:
Ok, the data is received with UDP socket. it is 68 in length. The device documentation doesn't specify any methods to capture this data, because may be it is designed to work with the specified application. We can't contact the manufacturer also. is there any way (if possible) to know the format of incoming bytes. we have tried network sniffers but we cant understand the format.
If you're receiving from the telnet command, then I suspect you have a network-specific issue.
your device isn't talking to the same ip address / hostname that you're configuring telnet with
you have a routing or firewall issue
is your device possibly using UDP rather than TCP ?
The java server socket is created but no incoming connections are received from the device.
So either there is a firewall in the way or the device isn't trying to connect to that port.
The java server socket is receiving connections from telnet command.
So the Java application is listening to that port.
The data format which is used by the device and the other native application may be different, but at least it has to be connected from java server socket. is it correct?
Yes.
how to receive the data which is transmitted to port 7777.
First you have to accept the connection. On the evidence here the device isn't connecting to port 7777 at all. I suggest some network sniffing is in order to see what it really is doing.