I have a server in Java which is multithreading, and I've created a thread pool for it.
Now everything goes well and my server accepts and reads data from the clients that connect to it, but I don't know really how to clean up the sockets after the connections are closed.
So here is my code:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
ThreadPooledServer server = new ThreadPooledServer(queue,7001);
new Thread(server).start();
}
ThreadPooledServer class:
public class ThreadPooledServer implements Runnable {
protected ExecutorService threadPool = Executors.newFixedThreadPool(5);
public ThreadPooledServer(BlockingQueue queue,int port) {
this.serverPort = port;
this.queue=queue;
}
public void run() {
openServerSocket();
while (!isStopped()) {
Socket clientSocket = null;
try {
clientSocket = serverSocket.accept();
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);
}
this.threadPool.shutdown();
System.out.println("Server Stopped.");
}
private synchronized boolean isStopped() {
return this.isStopped;
}
public synchronized void stop() {
this.isStopped = true;
try {
this.serverSocket.close();
}
catch (IOException e) {
throw new RuntimeException("Error closing server", e);
}
}
Here's what I don't understand: My while() loop that accepts for clients works as loong as isStopped is false.
When isStopped is set to true, my loop ends and then I shut down my thread pool, which is correct.
isStopped is set to true in onstop(){..............}....
Where should I call onstop()...?
Because in this moment I'm not using this method ,I'm not calling it and that means that I'm not cleaning correctly my threads.
WorkerRunnable class:
public class WorkerRunnable implements Runnable {
public WorkerRunnable(BlockingQueue queue2, Socket clientSocket2) {
// TODO Auto-generated constructor stub
this.clientSocket2 = clientSocket2;
this.queue2 = queue2;
}
public void run() {
try {
is = new ObjectInputStream(this.clientSocket2.getInputStream());
try {
while (!stop) {
System.out.println("Suntem in interiorul buclei while:!");
v = (Coordinate) is.readObject();
queue2.put(v);
}
} catch (Exception e) {
e.printStackTrace();
is.close();
clientSocket2.close();
}
is.close();
clientSocket2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stop() {
this.stop = true;
}
}
}
Here I have the same issue. How should I clean and close up my sockets correctly?
Once you call shutdown() the thread pool will close off each thread once all the tasks are complete.
You should call onstop() from whatever code knows the pool should be shutdown. This depends on what the rest of your application does and why you would stop the pool before the application has finished.
Related
I have a basic server thread in which I accept sockets with the accept () function. For a certain period of time, I would need to avoid connecting new sockets. I want to do this from another thread by telling the server thread to not make new connections.
public class ServerThread extends Thread {
private boolean running = false;
private final ConnectionManager connectionManager;
private final AtomicBoolean acceptNewConnections;
ServerThread(ConnectionManager connectionManager, int port) {
super("ServerThread");
this.connectionManager = connectionManager;
this.port = port;
this.acceptNewConnections = new AtomicBoolean(false);
}
// This is called from other threads
public void setAcceptNewConnections(boolean value) {
acceptNewConnections.set(value);
}
#Override
public void shutdown() {
acceptNewConnections.set(false);
running = false;
try {
join();
} catch (InterruptedException ignored) {}
}
#Override
public void run() {
running = true;
connectionManager.serverThreadStart();
try (ServerSocket serverSocket = new ServerSocket(port)) {
acceptNewConnections.set(true);
while (running) {
try {
if (acceptNewConnections.get()) {
final Socket socket = serverSocket.accept();
if (acceptNewConnections.get()) connectionManager.addClient(socket);
else socket.close();
} else {
try {Thread.sleep(10);} catch(InterruptedException e){}
}
} catch (SocketTimeoutException ignored) {
//
}
}
} catch (IOException e) {
//
}
connectionManager.serverThreadStop();
}
}
My questions are:
Is there a way to interrupt waiting for a new socket while waiting?
Is there a way to wait for a new socket, but would accept it as needed after waiting for it, not wait and accept it in one command?
How can I pause the server thread while blocking new connections without using Thread.sleep() and useless overusage of cpu?
Thank you so much for help.
I have the following tcp server:
public class Server {
private Connection db;
private Statement statement;
private ServerSocket socket;
public static void main(String[] args) {
Server server = new Server();
server.initializeServer();
System.out.println("Server initialized");
server.listenConnections();
}
private void initializeServer() {
try {
db = DriverManager.getConnection("jdbc:mysql://localhost:3306/courseworkschema" +
"?verifyServerCertificate=false" +
"&useSSL=false" +
"&requireSSL=false" +
"&useLegacyDatetimeCode=false" +
"&" +
"&serverTimezone=UTC",
"Sergei",
"12345");
statement = db.createStatement();
socket = new ServerSocket(1024);
} catch (SQLException | IOException e) {
e.printStackTrace();
}
}
private void listenConnections() {
System.out.println("Listening connections ... ");
while (true) {
try {
Socket client = socket.accept();
new Thread(() -> {
System.out.println("Client accepted");
try {
OutputStream outputStream = client.getOutputStream();
InputStream inputStream = client.getInputStream();
String clientAction;
String queryContent;
boolean flag = true;
while (flag) {
byte[] msg = new byte[100];
int k = inputStream.read(msg);
clientAction = new String(msg, 0, k);
clientAction = clientAction.trim();
msg = new byte[100];
k = inputStream.read(msg);
queryContent = new String(msg, 0, k);
queryContent = queryContent.trim();
System.out.println(clientAction);
System.out.println(queryContent);
if (clientAction.equalsIgnoreCase("END")) {
flag = false;
}
else if (clientAction.equalsIgnoreCase("LOGIN")) {
System.out.println("Login action");
}
}
} catch (IOException e) {
e.printStackTrace();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
This server is created to communicate with database. Here's the way how I try to connect to this serverL
public class LoginController {
private LoginWindow window;
private Socket socket;
private InputStream is;
private OutputStream os;
public LoginController() {
connectToServer();
}
public void logInUser(String login, String password) {
if (!login.isEmpty() && !password.isEmpty()) {
sendDataToServer("LOGIN");
sendDataToServer("");
} else {
window.showMessageDialog("Fill the fields!", JOptionPane.ERROR_MESSAGE);
}
}
public void attachView(LoginWindow window) {
this.window = window;
}
private void connectToServer() {
try {
socket = new Socket("127.0.0.1", 1024);
System.out.println("Connected");
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendDataToServer(String res) {
try {
os = socket.getOutputStream();
os.write(res.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
When I run the server and then client, I have such logs in server:
Server initialized
Listening connections ...
Process finished with exit code -1
So, I can't understand why server doesn't wait and accept a connection from client, but closes after initializing and listening. So, what's the matter? I will appreciate any help. Thanks in advance!
UPD
When I run my app it started to work but I found out that code in Thread block isn't executed. I even can't understand, why does it happen
In your private void listenConnections() you are creating a Thread object but you are not telling it to start after its created thus it wont execute.
Your thread creation line should look something like this:
new Thread(() -> {
//your code
}).start();
From the javadocs:
https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#start()
public void start()
Causes this thread to begin execution; the Java Virtual Machine calls
the run method of this thread. The result is that two threads are
running concurrently: the current thread (which returns from the call
to the start method) and the other thread (which executes its run
method).
It is never legal to start a thread more than once. In particular, a
thread may not be restarted once it has completed execution.
Throws: IllegalThreadStateException - if the thread was already
started.
See Also: run(), stop()
I tried finding a question that covered my problem, but all I could find were lots of similar questions, but no answer that solved my problem.
I am creating a java webapp for Tomcat, that, between other things, must also act as a TCP server that handles multiple incoming connections: to do so, I run the TCP server code in a separate thread, which in turn uses a ExecutorService to create threads for each connection. The problem basically is that, when I stop Tomcat, the server thread never gets stopped (even if no one has connected yet) and hangs Tomcat, until I close the related process in the Task Manager.
So, this is the starting point of the program:
private TCPServer tcpServer;
Thread serverThread;
#Override
public void init() throws ServletException {
DBConn = getDBConn();
if (DBConn != null) {
//initiates loggers, reads configurations from a file, etc
//starts TCP server
tcpServer = new TCPServer(50001, 200);
serverThread = new Thread(tcpServer);
serverThread.start();
//will be doing other stuff
} else {
//handles DB connection failure
}
}
This is the TCPServer class:
public class TCPServer implements Runnable {
private final int listeningPort;
PrintWriter out;
BufferedReader in;
ServerSocket serverSocket;
private final ExecutorService pool;
public TCPServer(int port, int poolSize) {
listeningPort = port;
pool = Executors.newFixedThreadPool(poolSize);
}
#Override
public void run() {
LinkedBlockingQueue<Socket> queue = new LinkedBlockingQueue<>();
try {
serverSocket = new ServerSocket(listeningPort);
while (!Thread.currentThread().isInterrupted()) {
pool.execute(new ConnectionHandler(queue));
queue.put(serverSocket.accept());
}
} catch (IOException | InterruptedException ex) {
Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
private class ConnectionHandler implements Runnable {
private LinkedBlockingQueue<Socket> socketQueue;
public ConnectionHandler(LinkedBlockingQueue<Socket> queue) {
this.socketQueue = queue;
}
#Override
public void run() {
while (!Thread.interrupted() || !Thread.currentThread().isInterrupted()) {
try (Socket clientSocket = socketQueue.take()) {
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String line = in.readLine();
System.out.println("Incoming: " + line);
clientSocket.close();
} catch (InterruptedException ex) {
Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public void close(){
Thread.currentThread().interrupt();
try {
serverSocket.close();
} catch (IOException ex) {
Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null, ex); }
pool.shutdownNow();
}
}
I added, in the main class (the same where the init() above is), this override, that runs when Tomcat gets closed:
#Override
public void contextDestroyed(ServletContextEvent sce) {
serverThread.interrupt();
tcpServer.close();
ServletContextListener.super.contextDestroyed(sce);
}
I made so many edits trying to implement solutions that I found around on the internet, that surely some of this code is probably redundant or useless.
Can someone give me pointers on what I should do to correctly stop the TCPServer thread?
Thanks to this answer and Kayaman's comment, I revised the whole code and somehow got it working.
The init() override is the same, while the contextDestroyed override now is
#Override
public void contextDestroyed(ServletContextEvent sce) {
tcpServer.close();
serverThread.interrupt();
ServletContextListener.super.contextDestroyed(sce);
}
The TCPServer class now is:
public class TCPServer implements Runnable {
private final int listeningPort;
PrintWriter out;
BufferedReader in;
ServerSocket serverSocket;
private final ExecutorService pool;
public TCPServer(int port, int poolSize) {
listeningPort = port;
pool = Executors.newFixedThreadPool(poolSize);
}
#Override
public void run() {
try {
serverSocket = new ServerSocket(listeningPort);
while (!Thread.currentThread().isInterrupted()) {
Socket clientSocket = serverSocket.accept();
pool.submit(new ConnectionHandler(clientSocket));
}
} catch (IOException ex) {
Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null, ex);
} finally {
pool.shutdown();
}
}
private class ConnectionHandler implements Runnable {
private Socket sock;
public ConnectionHandler(Socket sock){
this.sock = sock;
}
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try{
in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
String line = in.readLine();
System.out.println("Incoming: " + line);
sock.close();
} catch (IOException ex) {
Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public void close(){
try {
serverSocket.close();
} catch (IOException ex) {
Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I would like to test the connection between a client and a server in a ScheduledExecutorService every x ms while processing received data from the distant host.
So I did something like this:
public class MyClass {
private final ScheduledExecutorService _timer = Executors.newScheduledThreadPool(1);
private Socket _connection;
public void connectToDistantHost() {
try {
_connection = new Socket();
_connection.connect(_adresseServeur);
new Thread(new Runnable() {
#Override
public void run() {
try {
//let another object know the connection is ok
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
_timer.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
testConnection();
}
}, 0, 200, TimeUnit.MILLISECONDS);
}
private void testConnection() {
//would like to peek on the socket's inputstream to know if something's wrong
}
private void myProcessing() {
while (true) {
...
//read what's inside stream
//process it in a thread
}
}
}
So, if I .read() on the Socket's inputstream it'll screw myProcessing(). I thought about wraping the inputstream in a BufferedReader and mark the buffer position before I read and then reset the position, but as the testing and the processing are in two differents thread it won't work anyway.
How can I do that? Knowing that I did it in c# without much problem:
class TraitementEnvoiClient {
...
private void testConnection(Object obj, ElapsedEventArgs args) {
_connectionIsOk = _connexionAuServeur.IsConnected();
if (!_connectionIsOk) {
tryToReconnect();
}
}
}
public static class ExtensionTcpClient {
//Credit to ElFenix: http://social.msdn.microsoft.com/Forums/en-US/c857cad5-2eb6-4b6c-b0b5-7f4ce320c5cd/c-how-to-determine-if-a-tcpclient-has-been-disconnected?forum=netfxnetcom
public static bool IsConnected(this TcpClient client) {
// Detect if client disconnected
try {
if (client.Client.Poll(0, SelectMode.SelectRead)) {
byte[] buff = new byte[1];
if (client.Client.Receive(buff, SocketFlags.Peek) == 0) {
// Client disconnected
return false;
}
}
} catch (SocketException se) {
return false;
}
return true;
}
}
Thank you
Edit: I would like to make something like that:
private static boolean isConnected(Socket client) {
try {
InputStream is = client.getInputStream();
if(is.peek() == -1) return false;
OutputStream os = client.getOutputStream();
os.write(new byte[]{}); //if it fails a IOException will trigger
} catch(SocketException se) {
return false;
} catch(IOException ioe) {
return false;
}
return true;
}
The testing is redundant. The read or write operations will return -1 if the other end closes or disconnects before or during the operation. There is no point in "testing" the connection first because it may subsequently fail during your IO operation.
See also the other answer mentioned in the comments.
Here is the code:
public static void main(String[] args) {
SocketWorker worker = null;
MyIOConsole mio = null;
try {
portNumber = 2012;
worker = new SocketWorker();
worker.assignPort(portNumber);
mio = new MyIOConsole();
mio.assignObject(worker);
Thread b = new Thread(mio);
b.start();
worker.run();
} catch (IOException e) {
e.printStackTrace();
}finally{
mio.applicationQuit();
}
}
The SocketWorker is simply a socket, listening the port 2012, and the MyIOConsole, will accept user command,
public class MyConsoleIO implements Runnable {
SocketWorker o;
static BufferedReader reader;
public void assignObject(Object o) {
reader = new BufferedReader(new InputStreamReader(System.in));
this.o = (SocketWorker) o;
}
#Override
public void run() {
String inputString = null;
System.out.println("Press 'q' to kill to program");
try {
inputString = reader.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (inputString.equalsIgnoreCase("q")) {
this.applicationQuit();
}
}
public void applicationQuit(){
this.o.stopWorking();
System.exit(0);
}
}
But when the Socket got the exception, even I catch them, the code
mio.applicationQuit();
keep run. I don't want that, I just want when the user close or crashed the application, the socket will close and quit. How can I solve it?
Add the following. The run method will be called as the JVM is exiting.
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run(){
// cleanup code before JVM exit goes here.
}
});