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.
Related
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.");
}
We've developed a Java application that sends several UDP datagrams to the very same destination IP address. Obviously the destination port is always the same one, but we can't seem to be able to set the source port to remain the same on each datagram.
If the data package we send is bigger than MTU the package is properly splitted over the same source port, but once we send a new data package the source port changes, generating a new firewall session (which network admin has warned us to be very bad due to the amount of sessions the application is generating).
Right now we're sending the packages with the following statement:
We've tried several approaches and the result is always the same, we can't seem to be able to set the source port to a fixed value.
Edit- pasting actual code:
private boolean sendImage(byte[] imageData, InetAddress address,
int port) throws UnknownHostException, SocketException {
boolean ret = false;
DatagramSocket socket = null;
try {
socket = new DatagramSocket();
DatagramPacket dp = new DatagramPacket(imageData, imageData.length, address, PUERTO_UDP);
socket.send(dp);
ret = true;
} catch (IOException e) {
Main.lanzarExcepcion(e);
ret = false;
} finally {
if (socket != null) {
socket.close();
}
}
return ret;
}
Thanks for your time!
I think your issue is that you are closing the actual DatagramSocket instead of reusing the same , and simply call socket.send(DatagramPacket). If you cant keep the client socket open , then you could even define the clients port like : DatagramSocket clientSocket = new DatagramSocket(9743); so each time you are calling a new clientSocket , it will get the same port or it will throw a java.net.BindException: Address already in use: Cannot bind
This will not solve the network sessions issue, because you are opening a new UDP Socket. Also i suspect that your network admin , sees the previous sessions , because you are not closing the UDP Sockets at all , but simply spawning them
As mentioned by #AntJavaDev
The solution was to:
1.- keep the DatagramSocket open
2.- pass src port in the arguments
3.- reusing the unclosed DatagramSocket for every new data packet to the same destination!
Thanks all!
The source port is an ephemeral port, generated for you by the underlying networking implementation. There is no reason to set it to a particular port number.
At this point, I am testing a webserver client/host system to be run on my raspberry pi (host) and on my pc (client). The basic idea is that every 5 seconds, the client on my pc sends a message to the host located at "192.168.0.11" at port 7051. It processes it and sends a message back to my pc.
For this I am using the following client code:
public static String getData() throws Exception {
try {
Socket socket = new Socket(SERVER_ADDRESS, SERVER_PORT);
socket.setReuseAddress(true);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
int msg = 71;
out.write("TEALBEE_CUR:" + msg);
out.flush();
String input;
String data = "";
while ((input = in.readLine()) != null) {
data += input;
}
socket.close();
return data;
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
return null;
}
The problem here is that while data-flow is consistent and can run for at least a week; I lost use of other sockets connections on my pc, namely my Kodi remote control (this is media centre which I can control through a socket connection on my smartphone). My pc at address "192.168.0.37" accepts connections at port 193 for Kodi but after running the Java client for some time and sending a lot of requests to the server, I notice that the remote cannot connect anymore to my PC.
I thought that this might be the case because the sockets cannot be reused and after a single use the socket becomes unusable. This does seem to be the case as my host detects a different socket port for each request.
I tried to solve this by adding the code socket.setReuseAddress(true) and properly closing the socket after each message, but the problem still occurs.
How can I fix this properly (if possible only use one client socket and close this properly so it can be used again the next time).
EDIT: also important to note I can access 192.168.0.37:193 from my PC, but not from my smartphone when the socket connection cannot be established. Yes I am sure that the PC and smartphone and RPI are on the same network and without the client program running I CAN access 192.168.0.37:193 from my smartphone.
I have this socket implementation in java which uses timeout:
try {
socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), 5000);
} catch (SocketException e2) {
System.out.println("Something wrong with the socket: " + e2);
}
The ip and port is closed, so connection cannot be made.
But the timeout here does not work. It does not wait for 5 seconds and then return an error.
This code is located in constructor and calls from runnable class. May this be the reason?
The connect timeout is the maximum time that connect() will block for. If there is an immediate connection refusal or other error, you will get it immediately. In this case the target port wasn't listening so you would have got an immediate ConnectException: connection refused. It isn't obliged to wait for the timeout if the error happens sooner. The timeout is really for where there is no response at all. Waiting after an error doesn't make any sense.
Socket socket = new Socket();
// This limits the time allowed to establish a connection
// timeout takes place if connection result is not received with in the specified timeout.
socket.connect(new InetSocketAddress(host, port), timeout);
// This stops the request for waiting for response after connection succeeds.
socket.setSoTimeout(timeout);
Good Day,
I was taking a look at this tutorial to do a TCP Threadpool server.
http://tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html
It works great for listening/RECEIVING to clients and processing, and returning a response. There is a class inside that I pass in WorkerRunnable into, and that basically prints out the remote socket address (who it was sent from)
public void run(){
synchronized(this){
this.runningThread = Thread.currentThread();
}
openServerSocket();
while(! isStopped()){
Socket clientSocket = null;
try {
clientSocket = this.serverSocket.accept();
} catch (IOException e) {
if(isStopped()) {
System.out.println("Server Stopped.") ;
return;
}
throw new RuntimeException(
"Error accepting client connection", e);
}
this.threadPool.execute(
new WorkerRunnable(clientSocket,
"Thread Pooled Server"));
}
this.threadPool.shutdown();
System.out.println("Server Stopped.") ;
}
The problem is. The remote address is supposed to stay fixed (I am working within my own home wifi router). However, the IP address of the sender stays the same, but the port keeps changing!!
This is a big problem for me..as I need to be able to return a response to the user for future tasks and I actually save this address to use again to send data. When I ran this in a single TCP thread..it stayed fixed (the port).
Why does the threadpool cause the TCP remote address port to keep changing?
With TCP, the client socket port is most of the time (almost 99%, except for specific protocols) randomly chosen. But to you don't have to know it, the only thing you have to do is to keep the clientSocket reference to write back data to the client. If you want to send data to the other host after that the connection is closed, you have to start a ServerSocket on both sides with a fixed port.
Even if you test from same machine the client port will be random by default. I am not sure if there is any way to set the client source port. However, if you use netstat or capture the packet you can be sure the source port is different for every connection.