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);
}
}
}
Related
I'am creating application to making screenshots via LAN. Server is
listening for clients. When client is connect, new thread is created and it shoud be added to a list. Admin on server can pick client from list, make screenshot on its computer and screenshot is sent to server. The problem is the list. How to make this list available in many places in app and it was always synchronized with all components that use it ?
I am using JavaFX. I readed about SimpleListProperty, but the problem was "how to use this instance in server thread?". I've tried with singletone variations, dependencies injection like Guice, Ignite, Spring, but it was generated many troubles and finally doesn't work :(
Server implementation
public class SocketServer extends Thread {
private ServerSocket serverSocket;
#Override
public void run() {
startServer();
}
private void startServer() {
try {
serverSocket = new ServerSocket(2345);
} catch (IOException e) {
e.printStackTrace();
}
while (true) {
try {
new EchoClientHandler(serverSocket.accept()).run();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void stopServer() {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public class EchoClientHandler extends Thread {
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
public EchoClientHandler(Socket socket) {
this.clientSocket = socket;
}
#Override
public void run() {
try {
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
//there shoud be somethink like:
// list.add(this);
}
public void close() {
try {
in.close();
out.close();
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//Getters and setters
MainController
public class MainController {
#FXML
private LogPaneController logPaneController;
#FXML
private ConnectionPaneController connectionPaneController;
#FXML
private ButtonsPaneController buttonsPaneController;
private Connector connectorImpl;
public void initialize() {
createConnector();
}
private void createConnector() {
ObservableList<Client> observableList = connectionPaneController.getConnectedClientsTable().getItems();
connectorImpl.setClientSimpleListProperty(observableList);
}
Connector
public class ConnectorImpl implements Connector {
private List<SocketServer.EchoClientHandler> clientsThreads;
private SimpleListProperty<Client> clientSimpleListProperty;
public ConnectorImpl() {
}
public static Client parseThreadToClient(SocketServer.EchoClientHandler clientThread) {
Socket socket = clientThread.getClientSocket();
PrintWriter out = clientThread.getOut();
BufferedReader in = clientThread.getIn();
return new Client(socket, out, in);
}
#Override
public void connectNewClient(SocketServer.EchoClientHandler clientThread) {
clientsThreads.add(clientThread);
clientSimpleListProperty.add(parseThreadToClient(clientThread));
}
//Getters and setters
}
App view
I'd like to synchronize my app because sometimes server send messages to wrong user. I use synchronized block to synchronize queue but my solution doesn't work - sometimes user receive message not for him.
Here is the code (server.java):
(InWorker - receive messages from users, OutWorker - send messages to users) every user has own class (thread) - MiniServer (contain two threads: InWorker and OutWorker).
class InWorker implements Runnable{
String slowo=null;
ObjectOutputStream oos;
ObjectInputStream ois;
ConcurrentMap<String,LinkedBlockingQueue<Message>> map=new ConcurrentHashMap<String, LinkedBlockingQueue<Message>>();
Message message=null;
InWorker(ObjectInputStream ois,ConcurrentMap<String,LinkedBlockingQueue<Message>> map) {
this.ois=ois;
this.map=map;
}
public void run() {
while(true) {
//synchronized(queue) {
try {
message = (Message) ois.readObject();
slowo=message.msg;
if(slowo!=null && !slowo.equals("Bye")) {
if(!map.containsKey(message.id)) {
map.putIfAbsent(message.id, new LinkedBlockingQueue<Message>());
try {
map.get(message.id).put(message);
} catch (InterruptedException ex) {
Logger.getLogger(Communicator.class.getName()).log(Level.SEVERE, null, ex);
}
}
else
{
try {
map.get(message.id).put(message);
} catch (InterruptedException ex) {
Logger.getLogger(Communicator.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//}
Thread.yield();
}
}
}
class OutWorker implements Runnable{
String tekst=null;
ObjectOutputStream oos=null;
String id;
Message message;
ConcurrentMap<String,LinkedBlockingQueue<Message>> map=new ConcurrentHashMap<String, LinkedBlockingQueue<Message>>();
OutWorker(ObjectOutputStream oos,String id,ConcurrentMap<String,LinkedBlockingQueue<Message>> map) {
this.oos=oos;
this.id=id;
this.map=map;
}
public void run() {
while(true) {
//synchronized(queue) {
if(map.containsKey(id)) {
while(!map.get(id).isEmpty()) {
try {
message=map.get(id).take();
} catch (InterruptedException ex) {
Logger.getLogger(OutWorker.class.getName()).log(Level.SEVERE, null, ex);
}
try {
oos.writeObject(message);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//}
Thread.yield();
}}}
Here is the MiniServer and Server class:
class MiniSerwer implements Runnable{
Socket socket=null;
ExecutorService exec=Executors.newCachedThreadPool();
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
String id;
Queue<Message> queue=new LinkedList<Message>();
MiniSerwer(ObjectOutputStream oos,ObjectInputStream ois,String id,Queue<Message> queue) {
this.oos=oos;
this.ois=ois;
this.id=id;
this.queue=queue;
}
public void run() {
exec.execute(new InWorker(ois,queue)); // input stream
exec.execute(new OutWorker(oos,id,queue)); //output stream
Thread.yield();
}
}
public class Serwer implements Runnable{
ServerSocket serversocket=null;
ExecutorService exec= Executors.newCachedThreadPool();
int port;
String id=null;
Queue<Message> queue=new LinkedList<Message>();
BufferedReader odczyt=null;
ObjectInputStream ois=null;
Message message=null;
ObjectOutputStream oos=null;
Serwer(int port) {
this.port=port;
}
public void run() {
try {
serversocket=new ServerSocket(port);
while(true) {
Socket socket=null;
try {
socket = serversocket.accept();
/* first message is login*/
oos=new ObjectOutputStream(socket.getOutputStream());
oos.flush();
ois=new ObjectInputStream(socket.getInputStream());
message = (Message) ois.readObject();
id=message.sender;
System.out.println(id+" log in to the server");
exec.execute(new MiniSerwer(oos,ois,id,queue)); // create new thread
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
int port;
port=8821;
ExecutorService exec=Executors.newCachedThreadPool();
exec.execute(new Serwer(port));
}
Can anyone help me ?
Edit: I change queue to ConcurrentHashMap but sometimes messages are send to the wrong user. Why ?
This is a classic producer/consumer scenario. ditch the synchronized blocks and use a BlockingQueue (InWorker calls put() and OutWorker calls take()).
also, in your Server class, you should be creating a new queue per connection, not sharing the same one across all connections.
My program is set & ready, the problem is within the server. When I clients send the message, where should it be stored at ? I tried using queue but didn't work, also tried to use a usual string register but it worked partially. I made a thread for the sending & a thread for storing, using "Read/write UTF". I would be more than grateful if somebody provided me with an algorithm , or at a least a better idea. Code :
class clientThread extends Thread {
DataInputStream fromClient;
int counter = 0;
public clientThread(Socket cs) throws IOException
{
fromClient = new DataInputStream(cs.getInputStream());
}
public void run()
{
while (true)
{
try {
toall=Integer.toString(counter)+fromClient.readUTF();
} catch (IOException ex) {
Logger.getLogger(ChatTerminalS.class.getName()).log(Level.SEVERE, null, ex);
}
counter++;
}
}
}
class SendingThread extends Thread
{
DataOutputStream toClient;
String s = "";int counter=0;
public SendingThread(Socket cs) throws IOException
{
toClient = new DataOutputStream(cs.getOutputStream());
}
public void run()
{
while (true)
{
if(toall.charAt(0)+""==Integer.toString(counter))
{}
else
{
try {
toClient.writeUTF(toall);
} catch (IOException ex) {
Logger.getLogger(ChatTerminalS.class.getName()).log(Level.SEVERE, null, ex);
}
counter++;
}
}
}
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.
Client has sendpoints() method which is called by some other class that I did not include.
Anyways, sendpoints() is called and sends integers to the server, which receives them and send back to all the clients that are connected to the server(broadcast).
The problem is, clients keep sending integers while server is stuck in the thread I created for receiving integers(I think the server is not reading from inputstream).
I tried changing the stream, I tried putting integers together in a object and send it with ObjectOutputStream but none of these seems to work.
I need help (pointStruct is a class that holds some integer values I created)
import java.net.*;
import java.util.*;
import java.awt.*;
import java.io.*;
import javax.swing.*;
public class Server {
private ArrayList dataclient;
private ArrayList messageclient;
private ServerSocket dataserver;
private ServerSocket messageserver;
public static void main(String[] args) {
Server s1 = new Server();
s1.start();
}
// Start running server
public void start() {
try {
dataserver = new ServerSocket(4999);
messageserver = new ServerSocket(5000);
Socket dataconn;
Socket messageconn;
dataclient = new ArrayList();
messageclient = new ArrayList();
dataconn= null;
messageconn= null;
System.out.println("[server]start");
//start accepting connections
while (true) {
try {
dataconn = dataserver.accept();
System.out.println("[server]accepted dataconn");
messageconn = messageserver.accept();
System.out.println("[server]accepted messageconn");
//add clients to arraylist
dataclient.add(dataconn.getOutputStream());
messageclient.add(messageconn.getOutputStream());
}
catch (Exception ex) {
ex.printStackTrace();
}
//creating receiver threads
Thread t1 = new Thread(new DataReceiver(dataconn));
Thread t2 = new Thread(new MessageReceiver(messageconn));
System.out.println("[server]Thread successfully created");
t1.start();
t2.start();
System.out.println("[server]Thread successfully started");
}
}
catch(Exception ex) {
ex.printStackTrace();
}
}
//receive data from clients
public class DataReceiver implements Runnable {
BufferedReader br;
InputStream is;
int x,y;
int x2,y2;
int t;
int red;
int green;
int blue;
int size;
int dummy;
DataReceiver(Socket s){
try {
is=s.getInputStream();
//br = new BufferedReader(isr);
}
catch(Exception ex) {
ex.printStackTrace();
}
}
public void run() {
while(true) {
try{
Iterator it = dataclient.iterator();
dummy=is.read();
if(dummy==9999) {
System.out.println("[server]executing data thread");
x=is.read();
System.out.println("[server]read a line"+x);
y=is.read();
System.out.println("[server]read a line"+y);
//x2=isr.read();
//y2=isr.read();
t=is.read();
red=is.read();
green=is.read();
blue=is.read();
size=is.read();
dummy=0;
//broadcast data
while (it.hasNext()) {
OutputStream os = (OutputStream)it.next();
os.write(9999);
os.write(x);
os.write(y);
os.write(t);
os.write(255);
os.write(0);
os.write(0);
os.write(size);
}
System.out.println("[server]data broadcasted");
}
}
catch(Exception ex) {
ex.printStackTrace();
}
}
}
}
//------------------------receive message from clients------------------------
public class MessageReceiver implements Runnable {
MessageReceiver(Socket s) {
}
public void run() {
}
}
}
public class networkHandler{
PrintWriter writer;
BufferedReader reader;
PrintWriter pwriter;
BufferedReader preader;
Socket sock;
Socket pointsock;
InputStream is;
JTextArea incoming;
pointHandler ph;
public networkHandler(pointHandler _ph) {
init();
ph=_ph;
setUpNetworking();
Thread readerThread = new Thread(new IncomingReader());
readerThread.start();
Thread pointerThread = new Thread(new ReceivingPoints());
pointerThread.start();
}
public void init() {
incoming = new JTextArea(20,20);
}
private void setUpNetworking() {
try {
// setup message port
System.out.println("networking establish started");
sock = new Socket("127.0.0.1",5000);
System.out.println("[NH]port 5000 established");
// setup point port
pointsock = new Socket("127.0.0.1",4999);
System.out.println("[NH]port 4999 established");
//message i/o stream
InputStreamReader streamReader = new InputStreamReader(sock.getInputStream());
reader = new BufferedReader(streamReader);
writer = new PrintWriter(sock.getOutputStream());
//point i/o stream
InputStreamReader pstreamReader = new InputStreamReader(pointsock.getInputStream());
System.out.println("networking establishing: Stream");
preader= new BufferedReader(pstreamReader);
pwriter= new PrintWriter(pointsock.getOutputStream());
System.out.println("networking establishing: Stream");
}
catch(IOException ex) {
ex.printStackTrace();
}
System.out.println("networking established");
}
//send message to the server
public void writeStream(String input){
try {
writer.println(input);
writer.flush();
}
catch(Exception ex) {
ex.printStackTrace();
}
}
public JTextArea getServerMessage() {
return incoming;
}
//receiving message from server
public class IncomingReader implements Runnable {
#Override
public void run() {
String message;
try {
while ((message = reader.readLine())!=null){
System.out.println("[NH] read from server:"+message);
incoming.append(message+"\n");
}
}
catch(Exception ex) {
ex.printStackTrace();
}
}
}
//receiving points from server
public class ReceivingPoints implements Runnable {
int x,y;
int x2,y2;
int red;
int green;
int blue;
int t;
int size;
int dummy;
pointStruct ps;
Color cr;
Point p;
synchronized public void run() {
try {
is = pointsock.getInputStream();
p= new Point();
}
catch(Exception ex) {
ex.printStackTrace();
}
while(true) {
try {
dummy=is.read();
if(dummy==9999) {
x=is.read();
y=is.read();
//x2=preader.read();
//y2=preader.read();
t=is.read();
red=is.read();
green=is.read();
blue =is.read();
size=is.read();
//create dummy pointStruct
ps = new pointStruct();
cr = new Color(red,green,blue);
p.x=x;
p.y=y;
ps.setP1(p);
p.x=x2;
p.y=y2;
//ps.setP2(p);
ps.setT((char)t);
ps.setS(size);
ps.setC(cr);
ph.save(ps);
dummy=0;
}
}
catch(Exception ex) {
ex.printStackTrace();
}
System.out.println("[NH]receiving done");
}
}}
public void sendPoints(pointStruct ps) {
OutputStream os;
try{
os=pointsock.getOutputStream();
os.write(9999);
os.write(ps.getP1().x);
os.write(ps.getP1().y);
//pwriter.print(ps.getP2().x);
//pwriter.print(ps.getP2().y);
os.write(ps.getT());
os.write(ps.getC().getRed());
os.write(ps.getC().getGreen());
os.write(ps.getC().getBlue());
os.write(ps.getS());
}
catch(Exception ex) {
ex.printStackTrace();
}
System.out.println("[NH]points sent to server");
}
}
You are reading the stream incorrectly, InputStream.read() returns a byte from the stream, but cast to an int.
InputStream.read() returns values from 0 to 255 is read is successful, and -1 if no more reading can be done (end of stream).
For example, InputStream.read() != 9999 always. So this ReceivingPoints.run() block will not fire:
while (true) {
try {
dummy = is.read();
if (dummy == 9999) {}
} catch(Exception ex) {
ex.printStackTrace();
}
}
You are looking for DataInputStream, it has methods for reading and writing other basic types than just bytes.