Using the default socket implementation on Windows, I was not able to find any effective method to stop Socket.connect(). This answer suggests Thread.interrupt() will not work, but Socket.close() will. However, in my trial, the latter didn't work either.
My goal is to terminate the application quickly and cleanly (i.e. clean up work needs to be done after the socket termination). I do not want to use the timeout in Socket.connect() because the process can be killed before a reasonable timeout has expired.
import java.net.InetSocketAddress;
import java.net.Socket;
public class ComTest {
static Socket s;
static Thread t;
public static void main(String[] args) throws Exception {
s = new Socket();
InetSocketAddress addr = new InetSocketAddress("10.1.1.1", 11);
p(addr);
t = Thread.currentThread();
(new Thread() {
#Override
public void run() {
try {
sleep(4000);
p("Closing...");
s.close();
p("Closed");
t.interrupt();
p("Interrupted");
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
s.connect(addr);
}
static void p(Object o) {
System.out.println(o);
}
}
Output:
/10.1.1.1:11
Closing...
Closed
Interrupted
(A few seconds later)
Exception in thread "main" java.net.SocketException: Socket operation on nonsocket: connect
You fork the thread and then the main thread is trying to make the connection to the remote server. The socket is not yet connected so I suspect s.close() does nothing on a socket that is not connected. It's hard to see what the INET socket implementation does here. t.interrupt(); won't work because the connect(...) is not interruptible.
You could use the NIO SocketChannel.connect(...) which looks to be interruptible. Maybe something like:
SocketChannel sc = SocketChannel.open();
// this can be interrupted
boolean connected = sc.connect(t.address);
Not sure if that would help though.
Related
public class Slave implements Runnable {
public ServerSocket slaveSocket;
public Slave(ServerSocket sk) {socket = sk;}
#Override
public void run() {
Socket client = slaveSocket.accept(); // slave will wait to serve a client
// more code...
Socket clientPart2 = slaveSocket.accept();
// more code...
}
}
public class Server {
public static void main(String[] args) {
// for example only, incomplete code
ServerSocket serverSocket = new ServerSocket(0); // a client connect to 8088
Slave slave = new Slave(serverSocket);
new Thread(slave).start(); // slave serve the current client, the server wait for new client
// send new slave's port to client ...
}
}
So I have a server that serves multiple clients at once. Whenever a client connects, the server will create a new Slave, send the IP/port of that slave to the client, then the client will work with the slave.
However, if the client receives the slave's address then do nothing (or quit) (Edit: it means the client and server are connected but the client do nothing, because for example the user goes for lunch) slaveSocket.accept() causes that slave Thread to run forever, which is wasteful.
I want the slave thread to exit after 30 second of waiting for slaveSocket.accept(). Since slaveSocket.accept() is blocking, I cannot do that from inside the void run().
What is the correct, clean way to solve this problem? Thank you.
Edit 1: a ServerSocket is passed to the slave because the client can have multiple processes that will connect to that slave. So it doesn't just perform one function.
If you set a timeout with setSoTimeout and no client connects, ServerSocket.accept will throw an exception. You can catch this exception.
To set a timeout of 30 seconds, use:
serverSocket.setSoTimeout(30000)
Non-blocking I/O:
Take a look at AsynchronousServerSocketChannel's accept method which returns a Future. Then the Future has a getter with timeout which can do what you are asking.
Note: you may read a related tutorial.
Then the getter will return an AsynchronousSocketChannel which can be converted back to blocking via the corresponding Channels.newInputStream and Channels.newOutputStream methods to be used with the blocking approach in the worker threads.
Blocking I/O:
I think you actually meant on how to implement a server which accepts clients sequentially and serves them in parallel, with blocking I/O. If that is the case, then you may take a look at the following example:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Objects;
public class Main {
public static class Worker implements Runnable {
private final Socket sck;
private OutputStream os;
private InputStream is;
public Worker(final Socket sck) {
this.sck = Objects.requireNonNull(sck);
}
#Override
public void run() {
try {
os = sck.getOutputStream();
is = sck.getInputStream();
//ALL the work with the client goes here, unless you need more than one connections with him.
}
catch (final IOException iox) {
System.err.println(iox);
}
finally {
try { is.close(); } catch (final IOException | RuntimeException x) {}
try { os.close(); } catch (final IOException | RuntimeException x) {}
try { sck.close(); } catch (final IOException | RuntimeException x) {}
}
}
}
public static void main(final String[] args) {
ServerSocket srv = null;
try {
srv = new ServerSocket(8088);
while (true)
new Thread(new Worker(srv.accept())).start();
}
catch (final IOException iox) {
System.err.println(iox);
}
finally {
try { srv.close(); } catch (final IOException | RuntimeException x) {}
}
}
}
My thread always stops after several days at serverSocket.accept(). Due to monitoring this thread with another thread I know that the thread state is still RUNNABLE after this problem.
Here a snippet of my code:
private ServerSocket serverSocket;
serverSocket = new ServerSocket(port, 50, addr);
serverSocket.setSoTimeout(180000); // 3 Minutes
public void run()
{
Socket server = null;
while(true)
{
try
{
server = serverSocket.accept(); //locks until a connection is made
}
catch(SocketTimeoutException s)
{
Util.showException(s);
continue;
}
}
}
The SocketTimeoutException will also not be thrown... btw. There is another try/catch around the whole while-loop... After it stops at serverSocket.accept() I get no exception.
First question here on StackOverflow, so please excuse me if I ask this incorrectly.
Basically, I'm writing a Multicast Client that indefinitely listens to a multicast address until the user types "quit" into the console. I've found that setting SO_TIMEOUT for the MulticastSocket, checking if "quit" has been typed, and then returning to the receive method call doesn't really work since a packet could be sent right after the timeout and the check of the console blocks. So I believe the best option is to simply have 2 threads going where one listens on the socket and blocks until it receives something, and the other thread listens to the console until told to quit. The only issue I have is that I'm unsure of how to go about having the console listening thread tell the socket thread to close the socket and terminate. System.end() would work but I fear that I'd leave a socket open, etc.
TLDR; Is there a way for the main method of a class to start a thread, and then respond a specific way once that thread ends? I need to listen to the console on one thread and a MulticastSocket on another, or just in the main of the client class.
Thanks everyone.
I would call Socket.close() to close the socket. This will produce an IOException in that thread. so before doing this I would set a flag like closed = true; and have the other thread check this before printing the error i.e. don't print an IOException if you have been closed. Something like this.
public class SocketListener implements Runnable, Closeable {
final MulticastSocket socket;
final Consumer<DatagramPacket> packetConsumer;
volatile boolean closed;
public SocketListener(MulticastSocket socket, Consumer<DatagramPacket> packetConsumer) {
this.socket = socket;
this.packetConsumer = packetConsumer;
}
#Override
public void run() {
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
try {
while(!closed) {
socket.receive(packet);
packetConsumer.accept(packet);
}
} catch (IOException e) {
if (!closed)
e.printStackTrace();
}
}
#Override
public void close() throws IOException {
closed = true;
socket.close();
}
}
for example, in your main thread you can do
MulticastSocket socket = ...
Consumer<DatagramPacket> packetConsumer = ...
try (SocketListener listener = new SocketListener(socket, packetConsumer)) {
boolean finished = false;
do {
// read from the console
if (some condition)
finished = true;
} while(!finished);
} // calls close() for you.
I am trying to open multiple ports on a server socket so that i could connect multiple clients. Each time i create a create a thread and start it (i know the overridden run method will be invoked) i open a port and listen for a client .
But the problem is that when i run the client socket project and try to connect to the port i opened in server ,it says java.net.connectException : connection refused:connect.
I also noticed a peculiar thing happenning.The output in the console window is different every time i run the "server code "
i have been working on this for the last 3 days and i have achieved nothing i guess.
note: this problem is unique for me as i have not found this particular problem on this forum any where so please be kind as i am a newbie to java and socket programming though i have been coding on c++ for quite some time now .
server socket
import java.io.*;
import java.net.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.*;
public class TryThreads extends Thread
{
private int Portnumber;
private static String inputLine;
public TryThreads(int portNumber)
{
Portnumber = portNumber;
setDaemon(true);
}
public static void main(String[] args)
{
//create three threads
Thread first = new TryThreads(63400);
Thread second = new TryThreads(63401);
first.start();
second.start();
//third.start();
System.out.println("ending main");
return;
}
public void run()
{
try
{
System.out.println("one socket port opened");
ServerSocket serverSocket = new ServerSocket(Portnumber);
System.out.println("one socket port opened");
while (true)
{
System.out.println("ending main2");
//System.out.println("one socket port opened");
Socket clientSocket = serverSocket.accept();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while((inputLine = bufferedReader.readLine()) != null)
System.out.println(inputLine);
}
}
catch(IOException e)
{
System.out.println(e);
}
}
}
client socket
import java.io.*;
import java.net.Socket;
public class client
{
private static PrintWriter printWriter;
public static void main(String[] args)
{
BufferedReader in = null;
try
{
Socket socket = new Socket("localhost",63400);
printWriter = new PrintWriter(socket.getOutputStream(),true);
printWriter.println("Hello Socket");
printWriter.println("EYYYYYAAAAAAAA!!!!");
}
catch(Exception e)
{
System.out.println(e);
}
}
}
In your TryThreads constructor, use:
setDaemon(false);
You have set your server threads to be daemon threads and they are therefore terminating as soon as main exits, so your server is stopping as soon as you start it.
See Thread.setDaemon():
The Java Virtual Machine exits when the only threads running are all daemon threads.
By the way, after the above issue is corrected, be aware that your implementation will lead to the server receiving a "connection reset" SocketException, which will break your server thread out of its loop and prevent it from accepting additional exceptions. You can fix this on the client side by doing socket.close() before you exit to ensure a graceful shutdown, but you will still want to fix it on the server side since you cannot assume that clients will be well-behaved.
Normally whenever you want to write a message using PrintWriter, you need to flush it when your done (printwriter.flush()). That makes sure the message is sent.
I got thread for server in my Android app and need to handle it properly when user decide to close it. I choose non-blocking ServerSocketChannel which accept() clients.
And got this
public class SocketServer extends Thread
{
private static final String LOG_TAG = "SocketServer";
private boolean isRunning = false;
private ServerSocketChannel listener = null;
public void _stop()
{
this.isRunning = false;
}
public void _start()
{
this.isRunning = true;
this.start();
}
private void free()
{
try
{
listener.close();
}
catch (IOException e)
{
//Error handle
}
listener = null;
}
public SocketServer(int port)
{
super();
try
{
listener = ServerSocketChannel.open();
listener.configureBlocking(false);
listener.socket().bind(new InetSocketAddress(port));
}
catch (IOException e)
{
//Error handle
}
}
public void run()
{
SocketChannel client = null;
while(isRunning)
{
try
{
client = listener.accept();//GC going mad
}
if(client != null)
Log.i(LOG_TAG, "ACCEPTED CLIENT");
catch (IOException e)
{
//Error handle
}
}
free();
}
All i'm doing is accepting new client - getting null because of no incoming connections and do it again until server is stopped.
ServerClient client is null at start and assigned to null by accept() if no connections available.
But Java's garbage collector thinks what client is somehow init by accept() or accept() somehow allocate some memory, which GC cleans after every while loop.
If comment accept() line (e.g do nothing) where will be no GC at all, so problem exactly in accept().
This quite not right in my opinion.
P.S. If there is some way to break blocking ServerSocket accept()/Socket read() state and exit properly, please tell me.
P.S. 2 Is it safe to write/ read to SocketChannel socket() as to Socket, will it block thread?
Many operations in Java create temporary objects internally to do their work.
You are much better off using a blocking SocketServer. This way the objects it creates is only on a per-accepted-Socket basis rather than a per-attempt basis.
I suggest you implement blocking NIO with a thread (or two) per connection first. If then you discover you have a performance issue with the number of threads you have, try using a Selector with non-blocking NIO.