Handling socket.close() gracefully - java

In my server located in a android device , if the number number of clients exceeds a specific number then the server close the socket. But in my client(other android device) i get a force close. How can i handle it gracefully?
Here is the connect part on my client:
serverIpAddress = serverIp.getText().toString();
if (!serverIpAddress.equals(""))
{
try
{
InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
SocketAddress sockaddr = new InetSocketAddress(serverAddr, 5000);
nsocket = new Socket();
nsocket.connect(sockaddr);
}catch(Exception e){
Log.i("Connect", "Connection Error");
}
if (nsocket.isConnected()){
score.setText("Your score is " + sc);
serverIp.setVisibility(View.GONE);
connectPhones.setVisibility(View.GONE);
enterIP.setVisibility(View.GONE);
Log.i("Connect", "Socket created, streams assigned");
Log.i("Connect", "Waiting for inital data..." + nsocket.isConnected());
receiveMsg();
}

Keep checking the socket connection is still open or not using isClosed() within an infinite loop, when server closes its connection, the isClosed() gets true, and then display a message or toast giving your desired reason to the user.

Sounds like whatever you are using to read the socket is a blocking read, and throws an exception when the socket closes and it is stuck at that read. Make sure that read is in a try block, and use the catch/finally to gracefully exit whatever you are doing at that moment.

Related

Socket won't send data after blocking queue .take()

Edit: I've found the problem ( see answer below )
I'm trying to write an Android application to send data to a running termux instance via TCP.
In termux, I have netcat listening for incoming TCP connections and printing data to stdout using the command nc -l localhost 8080.
In my android app, I have a thread that reads in strings from a blocking queue and writes them out to a socket connectd to the address that netcat is listening on. The relevant code is the following:
runnable = () -> {
Socket socket = null;
OutputStream socketOutStream = null;
while (running) {
try {
if (null==socket) {
socket = new Socket();
socket.setTcpNoDelay(true);
socket.setKeepAlive(true);
socket.connect(new InetSocketAddress("127.0.0.1", 8080), 2000);
socketOutStream = socket.getOutputStream();
socketOutStream.write("Hello, Server!".getBytes()); // [1] Works!!
socketOutStream.flush();
}
String message = queue.take();
socketOutStream.write(message.getBytes()); // [2] Doesn't work!!?
socketOutStream.flush();
socketOutStream.close();
Log.i(TAG, "We wrote 'Button Clicked!' to the socket I think.");
// running=false;
}
catch (IOException e) {
Log.e(TAG, e.toString());
socket = null;
}
catch (InterruptedException e) {
Log.e(TAG, e.toString());
Log.i(TAG, "Exiting socket sending loop.");
running = false;
}
}
};
Thread thread = new Thread(runnable);
thread.start();
I'm trying to figure out why the initial data sent to netcat at the line marked [1] is actually received and displayed inside termux, but any subsequent data sent at [2] is not. The incoming strings fetched from the queue are certainly not empty.
Additionally, if I move the socket instantiation and connection logic to occurr until after queue.take() returns, I see a SocketTimeoutException via adb log output.
I would like to understand why it should make any difference whether either of these operations shoud occurr before or after the queue.take() operation returns.
I was eventually able to resolve the issue with the TCP socket hanging by attaching the socket to a foreground service as opposed to a background service which is how it was running in the first instance. It seems Android background services are liable to have TCP communications delayed or buffered in order to economize battery usage.

Why TCP/IP server with listening port in java not working

I have written a code in java to interface my computer with a transmitter a transmitter device, with a communication board already implemented and ready to connect via TCP/IP to any server with a specific address IP (say 192.168.2.2) and listening to a specific port number (say 4000).
I followed the exact strep how to create a server side application in Java offering a that listening port, so that I can connect to that transmitter.
I don't understand why when I try to debug the code, it blocks a the line clientSocket = serverSocket.accept(), and throws a timeout exception.
Could someone help me find out where the error might be in my code?
Any help would be greatly appreciated.
Thanks.
Here is the code:
public class Server {
public static void main(String[] args) {
// TODO Auto-generated method stub
//Declares server and client socket, as well as the input and the output stream
ServerSocket serverSocket = null;
Socket clientSocket = null;
PrintWriter out;
//BufferedReader in;
BufferedReader in;
try{
InetAddress addr = InetAddress.getByName("192.168.2.2");
//Opens a server socket on port 4000
serverSocket = new ServerSocket(4000) ;
//Sets the timeout
serverSocket.setSoTimeout(30000);
System.out.println("Server has connected");
//Create a connection to server
System.out.println("Server listening connection from client ....");
//Listens and waits for client's connection to the server
clientSocket = serverSocket.accept();
// Creates input and output streams to socket
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
//Reads response from socket
while((in.readLine())!= null ){
System.out.println ( in.readLine() );
}
System.out.println ( "Closing connection ....");
//Terminates connection
clientSocket.close();
serverSocket.close();
System.out.println("Connecton successfully closed");
}
catch(IOException e){
System.out.println(e);
}
}
}
Could someone help me find out where the error might be in my code?
There is no error in your code that could cause this problem. Clearly you haven't configured the device to connect to this server correctly, or the device isn't running, or it isn't connecting, or there is a firewall in the way. Investigate that.
However:
InetAddress addr = InetAddress.getByName("192.168.2.2");
What is this for? It isn't used.
System.out.println("Server has connected");
This is simply not true. The server hasn't connected. At this point all it has done is create a listening socket.
while((in.readLine())!= null ){
Here you are reading a line and throwing it away.
System.out.println ( in.readLine() );
Here you are printing every second line, having thrown every odd line away. The correct way to write this loop is:
String line;
while ((line = in.readLine()) != null)
{
System.out.println(line);
}
Note also that this server will service exactly one client and then exit. There should be a loop around everything from accept() to clientSocket.close(), and if there are multiple devices it should start a new thread per accepted socket to handle the I/O.
You specified timeout of 30 seconds, didn't you? :
serverSocket.setSoTimeout(30000);
So after 30 seconds, no matter whether stopped in debugger or running, this will timeout and throw exception.

how to use socket.setSoTimeout()?

When you set a timeout on a socket with socket.seSoTimeout(5000); does the socket close or just stop listening after it times out? Will I have to open the socket again to continue listening or will it open automatically?
receivingSocket.setSoTimeout(5000); // set timer
try{
receivingSocket.receive(packet);
}
catch(SocketTimeoutException e){
System.out.println("### Timed out after 5 seconds.");
}
//will I have to reopen the socket here?
You can test your question by wrapping your try/catch in a while (true). The short answer is no, you do not have to reopen the socket. The setSoTimeout() is just telling the socket to wait this long for data before you try to do anything else.
byte[] buffer = new byte[1000];
DatagramPacket p = new DatagramPacket(buffer, buffer.length);
DatagramSocket receiveSocket = new DatagramSocket(5505, InetAddress.getByName("127.0.0.1"));
receiveSocket.setSoTimeout(5000);
while (true) {
try {
receiveSocket.receive(p);
} catch (SocketTimeoutException ste) {
System.out.println("### Timed out after 5 seconds");
}
}
Results (You can see that the socket is still reusable after it timesout):
As the documentation states:
If the timeout expires, a java.net.SocketTimeoutException is raised, though the ServerSocket is still valid
So no, it will not close the socket. Next time you're wondering how something works, check out the documentation

Android socket connection with wrong IP causes freeze

I'm trying to create a socket that connects to a server. A user can manually enter the socket's IP address and IP port.
When the address and port are valid nothing goes wrong, but when they don't, it causes my entire app to freeze.
This is the code:
public void connect() {
try {
String txHostIP = settings.getString("txHostIP", "");
int txHostport = Integer.parseInt(settings.getString("txHostPort", ""));
//Where it all goes wrong. The program just hangs here for eternity
socket = new Socket(txHostIP, txHostport);
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
} catch (IOException e) {
showMessage(context, "Something went wrong");
}
}
What I want is for a message to pop up when no connection can be made but the program doesn't throw an exception if an IP port or address is incorrect.
How can I fix this? Any help is greatly appreciated!
EDIT:
I've added some System.out prints to show how the program hangs. I've also added a socket connect timeout of 5 seconds. Still the program won't even reach that block of code.
public void connect() {
try {
String txHostIP = settings.getString("txHostIP", "");
int txHostport = Integer.parseInt(settings.getString("txHostPort", ""));
System.out.println("1");
socket = new Socket(txHostIP, txHostport);
System.out.println("2");
socket.connect(socket.getLocalSocketAddress(), 5000);
System.out.println("3");
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
System.out.println("4");
} catch (IOException e) {
showMessage(context, "Something went wrong");
}
}
It just prints the 1 and then hangs on forever.
If you want to let the socket abort after a certain amount of time you have to do this:
int timeout = 5000;
int port = 1234;
String address = "localhost";
InetSocketAddress inetAddress = new InetSocketAddress(address, port);
Socket socket = new Socket();
socket.connect(inetAddress, timeout);
Otherways the socket will hang before you set the soTimeout. The connect method will throw an SocketTimeoutException if the remote host is not reachable.
Set a connection timeout of say, 5 seconds - run a counter based on the system clock and when the time is up, if it hasn't connected - throw the exception and cancel the connection.

Java socket read timeout exceptions

I try to overcome a user disconnection detection on the server side using read timeout.
This is part of my code:
try {
socket.setSoTimeout(3000);
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
usr = new User(in.readUTF());
usr.connectUser();
int i=0;
while(true){
try{
i = in.readInt();
}
catch(SocketTimeoutException e){
System.Out.Println("Timeout");
// user connected, no data received
}
catch(EOFException e){
System.Out.Println("Disconnected");
// user disconnected
}
}
}
catch(Exception e){
// other exceptions
}
the code works fine except the "user disconnected" issue.
i want to catch the timeout exception and just continue waiting for data
but only if the client still connected.
why i never get other exception than SocketTimeoutException?
shouldn't i get IOException while in.readInt() can't use the socket because client disconnected?
is there any other simple way to detect user disconnection?
i mean as unwanted disconnection, like user had suddenly wifi shutdown etc...
thanks,
Lioz.
If the client didn't write anything within the timeout period, you get a SocketTimeoutException. If he disconnected instead of writing anything, you get an EOFException. Catch them separately. If you didn't get an EOFException, he didn't disconnect.

Categories