I have a GUI with a list of servers to connect to. If a user clicks a server it connects to it. If a user clicks a second server, it will disconnect the first and connect to the second. Each new connection runs in a new thread so that the program can perform other tasks.
However, if a user clicks a second server while the first is still connecting, there are two simultaneous connections.
I'm connecting using this, and connect() is the line that blocks:
Socket socket = new Socket();
socket.connect(socketAddress, connectTimeout);
I thought maybe Thread.currentThread().interrupt(); would work, but didn't.
Do I have to restructure my code a bit so that it continues making the first connection, but closes it straight after? Or is there actually a way to interrupt the connect method.
If you are using a blocking socket implementation, interrupting the thread won't 'cancel' or interrupt your socket connection. The only way of breaking out of the 'blocking call' is to 'close' the socket. You can expose a method on your Runnable tasks (e.g. cancel) which close the socket and clean up the resources when the user tries connecting to a second server.
If you want you can have a look at my throwaway attempt at interrupting threads which make blocking calls.
Can you instead use a non-blocking socket? I'm not much of a Java expert, but it looks like SocketChannel is their non-blocking socket class.
Here is an example:
// Create a non-blocking socket and check for connections
try {
// Create a non-blocking socket channel on port 80
SocketChannel sChannel = createSocketChannel("hostname.com", 80);
// Before the socket is usable, the connection must be completed
// by calling finishConnect(), which is non-blocking
while (!sChannel.finishConnect()) {
// Do something else
}
// Socket channel is now ready to use
} catch (IOException e) {
}
Taken from here:
http://www.exampledepot.com/egs/java.nio/NbClientSocket.html
Inside the while loop you can check for some shared notification that you need to be cancelled and bail out, closing the SocketChannel as you go.
I tried the suggested answers but nothing worked for me.
So what I did was, instead of setting my connection timeout to 10 seconds I try to connect 5 times in a row with a connection timeout of 2 seconds.
I also have a global variable boolean cancelConnection declared.
Every time a timeout exception is thrown, I can eather break out of or continue the loop based on the value of cancelConnection.
Here's a code snippet from an android app I'm writing:
try {
SocketAddress socketaddres = new InetSocketAddress(server.ip,server.port);
int max=5;
for (int i = 1; i<=max; i++) {
try {
socket = new Socket();
socket.connect(socketaddres, 2000);
break;
} catch (Exception e) {
Log.d(TAG, "attempt "+i+ " failed");
if (cancelConnection) {
Log.d(TAG, "cancelling connection");
throw new Exception();
} else if (i==max) {
throw new Exception();
}
}
}
} catch (Exception e) {
if (cancelConnection) {
// Do whatever you would do after connection was canceled.
} else {
// Do whatever you would do after connection error or timeout
}
}
You can use something like this construction:
ExecutorService es = Executors.newSingleThreadExecutor(new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = Executors.defaultThreadFactory().newThread(r);
t.setDaemon(true);
return t;
}
});
Future<Socket> res = es.submit(() -> {
try {
return new Socket(addr, port);
} catch (Exception ex) {
logger.error("Error while connecting. " + ex.getMessage());
return null;
}
});
es.shutdown();
try {
while (!res.isDone()) {
Thread.sleep(5);
}
} catch (InterruptedException iex) {
logger.error("Connection interrupted.");
return;
}
Socket client = res.get();
Related
In my app, I open and close a Bluetooth socket on the same device each session and listen for data. When I close one, I make sure to close the input and output streams and then socket in a cancel method. Still, for some people the app keeps trying to read from the device. I know because I read logs that are from run() in the listening thread, where there is a flag for listening that's set to false in cancel, and the listening thread will end when the socket is closed due to an IOException, but this never happens, so the socket must still be opened. I see logs of attempted reads every second of every day even though the person isn't using the app. This might be because the app crashes and the cancel method isn't called. Either way I can't guarantee the cancel method will be called. How do I close any Bluetooth sockets that were previously opened when I start up my app, if these were all opened in new threads created independently?
This guy had the same problem but I didn't see any solution:
Android bluetooth connection doesn't close after application crash
The accepted answer is no good because:
The current users haven't had the UncaughtExceptionHandler run that code yet and they need to have any previous connections closed when the new version is released
The UncaughtExceptionHandler must have a reference to the sockets, which it doesn't have. I want to be able to close any Bluetooth sockets when the app starts.
The guy who made that question asked how to get information about the socket to store for when the app starts up and you want to close them, and got no response.
EDIT:
How I open the socket (removed logging code):
try {
tmp.connect();;
} catch (IOException e) {
isConnected = false;
try {
tmp = (BluetoothSocket) device.getClass().getMethod("createRfcommSocket",
new Class[] {int.class}).invoke(device, 1);
} catch (Exception e2) {
e2.printStackTrace();
}
try {
tmp.connect();
setConnected();
} catch (IOException e1) {
e1.printStackTrace();
isConnected = false;
cancel();
}
How I close the socket:
public void cancel() {
isConnected = false;
listening = false;
try {
if (manageConnection.mmInStream != null) {
manageConnection.mmInStream.close();
manageConnection.mmInStream = null;
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (manageConnection.mmOutStream != null) {
manageConnection.mmOutStream.close();
manageConnection.mmOutStream = null;
}
} catch (IOException e) {
e.printStackTrace();
}
try {
mmSocket.close();
mmSocket = null;
manageConnection = null;
} catch (IOException e) {
// Logging code
}
}
}
Listening:
while (listening == true) {
try {
synchronized (ListeningActivity.lock) {
buffer = new byte[mmInStream.available()];
mmInStream.read(buffer);
....
} catch (IOException e) {
// Code that calls cancel()
We created a server client relation between java (eclipse on windows/server) and android app (android studio/client). The communication seems fine, but sometimes the connecting is horrably slow, up to the point where the app and and server don't respond anymore. Yet, no real error is given and there is no pattern to when the connection goes well or when it is slow.
We looked for answers here at stack, but we could only find answers regarding the output and input streams. However, once the connection (serverSocket.accept()) is made, the program runs fine and the streams are created super fast. Thus we think the problem lies with the server side creation of sockets. The program only has to handle a maximum of 30 clients, and the only communication exists of strings (so no enormous data transfers).
Note: when one connection acceptation is slow, the next upcomming requests from clients have to wait. When it's their turn they are again randomely fast or slowly accepted by the server. All connections are made on port 8080.
The code of our server and client are given below, does anybody know why the connection is (at some random times) so slow?
SERVER:
public void run() {
keepGoing = true;
try {
serverSocket = new ServerSocket(port);
while (keepGoing) {
display("Server waiting for Clients on port " + port + ".");
Socket socket = serverSocket.accept(); //<---our problem
if (!keepGoing) break;
ClientThread t = new ClientThread(socket, this); //<---program doesnt reach this code when it is slow. One client thread exists for each connection.
}catch (IOException e) {
String msg = sdf.format(new Date())
+ " Exception on new ServerSocket: " + e + "\n";
display(msg);
}
}
CLIENT THREAD CODE: (not reached if slow)
public ClientThread(Socket socket, Server s) {
this.server = s;
this.socket = socket;
System.out.println("Thread trying to create Object Input/Output Streams");
try {
// make streams
sOutput = new ObjectOutputStream(socket.getOutputStream());
sInput = new ObjectInputStream(socket.getInputStream());
// read user account info
String input = (String) sInput.readObject();
String[] accountInfo = input.split(";");
username = accountInfo[0];
password = accountInfo[1];
} "catch all problems"
}
CLIENT (android)
Thread connect = new Thread(new Runnable() {
#Override
public void run()
{
try
{
socket = new Socket(ip.getText().toString(), portNr);
sOutput = new ObjectOutputStream(socket.getOutputStream());
sInput = new ObjectInputStream(socket.getInputStream());
}
catch (UnknownHostException e ){
e.printStackTrace();
} catch(IOException e ){
e.printStackTrace();
}
"sending account information"
}
});
connect.start();
try {
connect.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Thanks so much!
You should make the streams in the ClientThread in the run() method, before you start looping. Not in the constructor. Otherwise you are doing I/O in the accept thread, which slows it down.
I have no idea why you're creating a thread in the client only to join it immediately.
You should extract your main server loop (while(keepGoing)...) into a run method and make the server implement the Runnabel interface. Then create a new Thread and start it.
Example:
public class Server implements Runnable{
private Thread thread;
public Server(){
thread = new Thread(this);
thread.start(); //I would create start() and stop() methods but for simplicity I just use thread.start()
}
#Override
public void run(){
//while....
}
}
I hope you get what I want to say, otherwise just comment and I will upgrade my example ;)
Turns out we had a router issue. When connecting all tablets and computer to a local hotspot it ran super smooth! Tanks everyone for the help :D
EDIT: Try a BufferedStreamReader mentioned here: Java socket performance bottleneck: where?
Instead of:
sOutput = new ObjectOutputStream(socket.getOutputStream());
Use:
sOutput = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
and flush it with:
sOutput.flush();
Same goes for the InputStream, use BufferedInputStream.
I have a multithreaded TCP Server in Java which allows connections from several clients and starts a new ServerThread for each connected Client:
Server Class:
while (!Thread.currentThread().isInterrupted()) {
try {
// Create a new thread for each incoming connection.
Socket clientSocket = serverSocket.accept();
ServerThread serverThread = new ServerThread(clientSocket, this);
serverThread.run();
} catch (IOException e) {
e.printStackTrace();
}
}
After a specific timeout, a client closes its socket. How can I interrupt the ServerThread which was connected with the client?
clientsocket.isClosed() and !clientSocket.isConnected() don't work for some reason.
Finally, I got it working with the following snippets (the solution is the socket in the resource block and the endless in.readLine() == null):
Server class
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
// Create a new thread for each incoming connection.
Socket clientSocket = serverSocket.accept();
ServerThread serverThread = new ServerThread(clientSocket, this);
serverThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ServerThread class:
public void run() {
try (Socket socket = clientSocket; // Enable auto-close for socket...
PrintWriter out = ...; BufferedReader in = ...;) {
...
while (!clientSocket.isClosed() && !isInterrupted()) {
if (in.readLine() == null) {
break;
}
}
System.err.println("Client with port " + clientSocket.getPort() + " closed connection to server.");
} catch (IOException e) {
e.printStackTrace();
}
}
Client class: I use the same try with resource block as in the ServerThread class
If the client closes a TCP socket uncleanly without sending an explicit FIN (for example, if the client crashes) then the server will not know about it until it next tries to send a packet to the client (at which point the client will sent an RST packet to tell the server the socket was closed).
Assuming you have control of both client and server code, the most robust way to check the connection is to implement a heartbeat mechanism between the two so they are regularly pinging a small piece of data between them to check the validity of the connection.
Keep alive socket option is the standard way to watch persistent TCP connection.
If your server was in the blocking read operation during the abort you'll get java.io.IOException: read failed. In the asynchronous case you'll receive read key with -1.
In the write state you'll get: Connection reset by peer: socket write error.
Just handle the exceptions or error codes to shutdown the thread if connection is not recoverable.
I have two threads, one for reading, one for writing data through the same socket. When is problem with connection two threads catch exceptions and try reconnect.To do this they call the same methods
public synchronized void close_connection() {
try {
socket.shutdownInput();
socket.shutdownOutput();
socket.close();
try {
Thread.sleep(500);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
and after it second one to try establish connection:
public synchronized boolean connect() {
boolean result=true;
socket = new Socket();
try {
socket.connect(new InetSocketAddress(address, port), 500);
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()));
} catch (IOException e) {
result=false;
}
return result;
}
The problem is how to avoid trying connect with server from two threads one by one immediatly (after connection error - for example afrter closing connection by server). I mean: if one thread tries do connection the second thread should know this and dosen't try do the same but wait for establish connection by first one (to avoid permanent fight threads problem disconnect,connect, disconnect, connect....). I've tried with synchronization but my experience is too small.
Regards,
Artik
You could try something like this:
while(not connected){
try reconnecting
if(success){
//Everything is ok, go on
} else {
//sleep for random period of time and retry
}
}
or you can implement the socket operations in an object and share that object between your threads using locks.
Use appropriate mutex locking. This will make sure only one thread will access the connect() portion of your code.
I have a server in Java which listens for incoming connection to a specific port. And everything works as expected, my clients connect to the server and I'm able to send data between them.
My problem is that, when I shut down my client, turn it on again and try to reconnect, it won't connect (my server stays on all the time).
For me to reconnect, I have to restart my server again.
So I tried doing this on my server side:
InetSocketAddress serverAddr = new InetSocketAddress(serverIpAddress, serverPort);
serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
//I tries setting up a reuse option
serverSocket.bind(serverAddr);
Even after setReuseAddress() my client won't connect unless I restart my server!
Has anyone any idea of how could that be done?
EDIT2:
try {
while(true){
clientSocket = serverSocket.accept();
System.out.println("S-a conectat clientul de monitorizare!");
os=new ObjectOutputStream(clientSocket.getOutputStream());
try{
coord=(Coordinate)queue.take();
System.out.println(coord.getLat()+coord.getLon()+coord.getVit()+coord.getwId()+coord.getime());
os.writeObject(coord);
os.flush();
}
catch(Exception e)
{
e.printStackTrace();
}
}
} catch (IOException e) {
System.out.println(e);
try {
clientSocket.close();
os.close();
}catch(Exception e1) {
e1.printStackTrace();
}
}
New edit:
Thread pool server:
Main:
ThreadPooledServer server = new ThreadPooledServer(queue,7001);
new Thread(server).start();
ThreadPooledServer:
public class ThreadPooledServer implements Runnable {
protected ExecutorService threadPool =
Executors.newFixedThreadPool(5);
public void run() {
openServerSocket();
while (!isStopped()) {
Socket clientSocket = null;
try {
System.out.println("Serverul asteapta clienti spre conectare");
clientSocket = this.serverSocket.accept();
clientconnection++;
System.out.println("Serverul a acceptat clientul cu numarul:"
+ clientconnection);
} catch (IOException e) {
if (isStopped()) {
System.out.println("Server Stopped.");
return;
}
throw new RuntimeException("Error accepting client connection",
e);
}
WorkerRunnable workerRunnable = new WorkerRunnable(queue,clientSocket);
this.threadPool.execute(workerRunnable);
}
System.out.println("Server Stopped.");
}
public synchronized void stop() {
this.isStopped = true;
try {
this.threadPool.shutdown();
}
catch (IOException e) {
throw new RuntimeException("Error closing server", e);
}
}
private void openServerSocket() {
try {
InetSocketAddress serverAddr = new InetSocketAddress(SERVERIP,
serverPort);
serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(serverAddr);
} catch (IOException e) {
throw new RuntimeException("Cannot open port", e);
}
}
this.serverSocket.close();
In your run method you accept one client and then go in to an endless loop, trying to write data to the ObjectOutputStream. When the client closes the connection an exception is thrown because you can no longer write to the stream. At this point we're out of the endless loop(while(true) { .. }) and the run method ends.
If you want to keep accepting clients I suggest you move the while loop to the top of your code, above the accept to be exact.
Pseudo-ish code below(note: I'm not catching any exceptions etc.):
while (true)
{
// Wait for a client to connect..
Socket clientSocket = serverSocket.accept();
// Write to the client..
ObjectOutputStream os = new ObjectOutputStream(clientSocket.getOutputStream());
os.writeObject(coord);
os.flush();
}
Is your server single threaded for a purpose (do you only accept one client at a time) ? Usually, servers will spawn a separate thread for every connections, so it can listen more often for incoming connections, and so if the client's connection throws any errors, it won't affect the listening socket. At the moment, your server will listen to only one connection, and if an exception occurs handling the client's connection, simply move on and never listen again. In pseudocode, a typical server is like :
Server listening thread (main thread)
try {
create server socket and bind to port
while server is online
listen for incoming connections
if the client connection is accepted [1]
start client thread
catch exception
handle exception
finally
make sure the server socket is disconnected
cleanup
Server client connection thread
write to client socket to initialize connection
try
while scoket is opened
read data
data treatment
write response
catch exceptions
handle exception [2]
finally
close client socket
cleanup
[1] if your server handles only one client, it should refuse the connection, so the client doesn't wait for no reason
[2] if the exception is not about the socket, the client should be warned by a final write to the socket before closing it
Client thread (on the client's side)
try
connect to server
protocol handshake (optional) [4]
while socket is connected
client server communication
catch exception
handle excpetion
finally
close socket
[4] since the server should write to the socket first, the client should read from it for any welcome message or error messages before attempting to write anything.