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.
Related
So my problem is I have a client with a Runnable that readobjects in background from the socket. In the server i send multiple times objects like notifications updates etc by writeUnshared, but the client is only receiving them when I send a request back to server by writeUnshared.
\ClientThread.java\
public class ThreadClientInFromServer implements Runnable {
Socket socket;
ClientData clientData;
public ThreadClientInFromServer(Socket socket, ClientData clientData) {
this.socket = socket;
this.clientData = clientData;
}
#Override
public void run() {
ObjectInputStream in;
ObjectOutputStream out;
out = clientData.getOut();
in = clientData.getIn();
while (!socket.isClosed()) {
try {
Object object = in.readObject();
clientData.updateData(object);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
SendRequestClient.java Only when i send this request it refresh and come the updates,notifications,etc
public void sendRequest(Request request) {
try {
out.writeObject(request);
out.flush();
out.reset();
} catch (IOException e) {
System.out.println("[ERROR] ON SEND REQUEST!");
return;
}
}
On Server (KEEPALIVETCP.java) for example, he doesnt receive.
public class KeepAliveTCP implements Runnable {
ServerModel serverModel;
public KeepAliveTCP(ServerModel serverModel) {
this.serverModel = serverModel;
}
#Override
public void run() {
Request request = new Request(null, Constants.ACK);
while (!serverModel.getSocket().isClosed()) {
try {
for (SocketModel clients : serverModel.getModelClientes()) {
if (clients.getNome() != null) {
clients.getOut().writeUnshared(request);
clients.getOut().flush();
}
}
sleep(5000);
watchWhoFails();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Thanks in Advance!!!
EDIT : So I was trying to find a solution and come up with my cliente blocking the thread(ThreadClientInFromServer) when he uses scanner.next() on the menus(that user uses to browse on the application). So I dont really know how to solve this problem, if you guys know some solution for this!
Thanks.
This question already has answers here:
Why are empty catch blocks a bad idea? [closed]
(20 answers)
Closed 5 years ago.
I have 3 very small classes.
The main class:
import java.io.*;
public class ConnectionManager {
public static void main(String argv[]) {
try {
PipedOutputStream pout = new PipedOutputStream();
PipedInputStream pin = new PipedInputStream(pout);
Sender s = new Sender(pout, true);
Receiver r = new Receiver(pin, true);
System.out.println("Starting threads");
s.start();
r.start();
} catch (Exception e) {}
}
}
The Sender class
import java.io.*;
import java.util.Random;
public class Sender extends Thread {
ObjectOutputStream oos;
boolean primitive;
public Sender(OutputStream os, boolean primitive) {
try {
oos = new ObjectOutputStream(os);
} catch (Exception e) {}
this.primitive = primitive;
}
public void run() {
Random rand = new Random();
while (true) {
try {
System.out.println("Integer is being sent");
oos.writeInt(10);
Thread.sleep(1000);
} catch (Exception e) {}
}
}
}
And the Receiver class
import java.io.*;
public class Receiver extends Thread {
ObjectInputStream ois;
boolean primitive;
public Receiver(InputStream is, boolean primitive) {
try {
ois = new ObjectInputStream(is);
} catch (Exception e) {}
this.primitive = primitive;
}
public void run() {
System.out.println("Receiver is starting");
while (true) {
try {
int x = ois.readInt();
System.out.print("An int was read: " + x);
} catch (Exception e) {}
}
}
}
Please ignore seemingly unused variables like primitive and rand. They're holdovers from slightly different versions that I was testing out earlier and I was too lazy to remove them.
Anyway, when I run the main method in ConnectionManager, I get this as output:
Starting threads
Receiver is starting
Integer is being sent
Integer is being sent
Integer is being sent
Integer is being sent
Integer is being sent
Integer is being sent
Integer is being sent
Integer is being sent
//... ad infinitum
Why is the receiver thread not getting the messages that are piped through? What am I missing here?
In your code, there is an exception like java.io.IOException: Read end dead.
You are NOT able to spot because you are suppressing them with empty catch blocks.
The main point is that you need to change Sender and Receiver classes to use PipedOutputStream and PipedInputStream as shown below :
Sender class:
public class Sender extends Thread {
PipedOutputStream oos;
public Sender(PipedOutputStream os) {
try {
this.oos = os;
} catch (Exception e) {System.out.println(e);}
}
public void run() {
try {
System.out.println("Integer is being sent");
oos.write(10);
oos.close();
Thread.sleep(1000);
} catch (Exception e) {System.out.println(e);}
}
}
Receiver class:
public class Receiver extends Thread {
PipedInputStream ois;
public Receiver(PipedInputStream is) {
try {
this.ois = is;
} catch (Exception e) {System.out.println(e);}
}
public void run() {
System.out.println("Receiver is starting");
try {
int x = ois.read();
System.out.print("An int was read: " + x);
} catch (Exception e) {System.out.println(e);}
}
}
main() method:
public static void main(String[] args) throws Exception {
try {
PipedOutputStream pout = new PipedOutputStream();
PipedInputStream pin = new PipedInputStream(pout);
Sender s = new Sender(pout);
Receiver r = new Receiver(pin);
System.out.println("Starting threads");
s.start();
r.start();
} catch (Exception e) {
System.out.println(e);
}
}
OUTPUT:
Starting threads
Receiver is starting
Integer is being sent
An int was read: 10
As a side note, remember that, empty catch blocks are very bad practice as they hide the exceptions, so I strongly suggest not to use them in the code.
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);
}
}
}
My server closes after one clients disconnects,and I can write only one more message then it crashes.I wonder why,since I only close the client socket when it types "EXIT SERVER" .This is the exception it throws:
java.io.EOFException
This is my code :
import java.net.*;
import java.io.*;
public class ServerPeer extends Thread {
Socket _socket;
String username;
public ServerPeer(Socket _socket) {
this._socket = _socket;
}
public void sendMessage(String _username, String _message) throws IOException {
ObjectOutputStream _obj = new ObjectOutputStream(
_socket.getOutputStream());
_obj.writeObject(new Message(_username, _message));
_obj.flush();
}
public synchronized void run() {
try {
ObjectInputStream _ois = new ObjectInputStream(_socket.getInputStream());
Message _message;
while (_socket.isConnected()) {
_message = (Message) _ois.readObject();
String divide = _message.getAll().substring(0, _message.getAll().indexOf(":"));
username = divide;
Server.listofusers.add(username);
for (ServerPeer sp : Server.listofpeers) {
if (_message.getAll().contains("EXIT SERVER")) {
Server.listofpeers.remove(sp);
_socket.close();
}
if (_message instanceof PrivateMessage) {
PrivateMessage privm = (PrivateMessage) _message;
for (ServerPeer sp2 : Server.listofpeers) {
if (sp2.username.equals(privm.getReceiver())) {
sp2.sendMessage(divide, privm.getAll());
String priv = privm.getAll().replaceAll("/w", "");
System.out.println(priv);
break;
}
}
} else {
sp.sendMessage(divide, _message.getAll());
System.out.println(_message.getAll());
}
}
_ois = new ObjectInputStream(_socket.getInputStream());
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Server Class:
import java.io.*;
import java.net.*;
import java.util.*;
public class Server {
static ServerConfig _svconfig = new ServerConfig();
public static ArrayList<ServerPeer> listofpeers = new ArrayList<ServerPeer>();
public static ArrayList<String> listofusers = new ArrayList<String>();
public static int i = 0;
// final static int _mysocket;
public static void main(String[] args) {
try {
final int _mysocket = _svconfig.getPORTNumber();
System.out.println("Wainting for clients.....");
ServerSocket _serversocket = new ServerSocket(_mysocket, _svconfig.getCLIENTSNumber());
while (listofpeers.size() <= _svconfig.getCLIENTSNumber()) {
Socket _clientsocket = _serversocket.accept();
ServerPeer _serverpeer = new ServerPeer(_clientsocket);
_serverpeer.start();
listofpeers.add(_serverpeer);
}
_serversocket.close();
} catch (MissingKeyException e) {
e.printStackTrace();
} catch (UnknownKeyException e) {
e.printStackTrace();
} catch (InvalidFormatException e) {
e.printStackTrace();
} catch (ConnectException e) {
e.printStackTrace();
} catch (BindException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (SocketException e) {
System.out.println("You have been disconnected");
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
EDIT:
Exception thrown in the console of the client who disconnects:
java.io.EOFException
at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2328)
at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:2797)
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:802)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:299)
at ClientPeer.serverEcho(ClientPeer.java:35)
at ClientPeer.run(ClientPeer.java:44)
BUILD STOPPED (total time: 1 minute 26 seconds)
From what I can tell i'd guess your code is incorrect, but it hard to tell without more code.
At first glance it seems that if too many people connect to your server you just shut down the entire server not just those connections.
while (listofpeers.size() <= _svconfig.getCLIENTSNumber()) {
Socket _clientsocket = _serversocket.accept();
ServerPeer _serverpeer = new ServerPeer(_clientsocket);
_serverpeer.start();
listofpeers.add(_serverpeer);
}
_serversocket.close();
A better approach would be something like the following. If too many users try to connect, just close the users connection.
ServerSocket _serversocket = new ServerSocket(_mysocket, _svconfig.getCLIENTSNumber());
boolean alive = true;
while (alive) {
try {
//Keep accepting connection request
Socket clientRequest = _serversocket.accept();
//Check if too many user are connected
if (listofpeers.size() <= _svconfig.getCLIENTSNumber()) {
ServerPeer _serverpeer = new ServerPeer(_clientsocket);
_serverpeer.start();
listofpeers.add(_serverpeer);
}else{
//Reject connection if too many connected
clientRequest.close();
}
} catch (Throwable t) {
t.printStackTrace();
}
}
//When server dead close it down
_serversocket.close();
Hope this helps.
Your code must be exiting after the client thread is terminated, create a thread that has the server accept method that starts the client thread, something like this,
/**
*/
private class ServerListener extends Thread
{
/**
*/
public void run()
{
try
{
Socket clientSocket = socket.accept();
System.out.println("client connected => "+clientSocket.getInetAddress().getHostAddress());
ServerListener th = new ServerListener();
th.start();
ClientThread cth = new ClientThread(clientSocket);
cth.start();
clients.add(cth);
return;
}
catch (Exception e)
{
e.printStackTrace();
//Main.getInsatance().println(e);
//Main.getInstance().println("socket disconnected => "+clientSocket.getInetAddress().getHostAddress());
}
}
}
I have a little problem with reading and writing to Sockets in my Server/Client Java application. Server have connection to database. I want to send an object "Employee" consist User Data (Name, Surname, Password) to Server, then Server look up to database about this user and resend to Client information - positive (1) or negative (-1).
First, when I want to send an object Employee, I've got :
"java.net.SocketException: Software caused connection abort: socket write error"
I have my Firewall turned off.
Second, when I want to send and receive just int through writeInt - readInt method for test, I can't to read anything on Server.
What's the problem? Please help.
Code Server:
class ClientCommunication implements Runnable {
private Socket incoming;
public ClientCommunication(Socket clientSocket) {
incoming = clientSocket;
}
public void run() {
try {
synchronized (this) {
try {
serverObjectOutput = new ObjectOutputStream(
incoming.getOutputStream());
serverObjectInput = new ObjectInputStream(
incoming.getInputStream());
} finally {
incoming.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
synchronized(this) {
while (true) {
try{
int operation = serverObjectInput.readInt();
switch(operation) {
case 1:
Employee employee = (Employee) serverObjectInput.readObject();
String SelectUserDataSQL = "SELECT COUNT(*) AS COUNT FROM pracownik where Imie = ? AND Nazwisko = ? AND Haslo = ?";
PreparedStatement CheckEmployeeLogin;
CheckEmployeeLogin = conn.prepareStatement(SelectUserDataSQL);
CheckEmployeeLogin.setString(1, employee.getFirstName());
CheckEmployeeLogin.setString(2, employee.getLastName());
CheckEmployeeLogin.setString(3, new String(employee.getPassword()));
ResultSet resultSQL = CheckEmployeeLogin.executeQuery();
if (resultSQL.next())
if (resultSQL.getInt("COUNT") == 0)
serverObjectOutput.writeInt(1);
else serverObjectOutput.writeInt(-1);
break;
}
} catch(IOException | ClassNotFoundException | SQLException ex)
{
}
}
}
}
}
class ServerStart implements Runnable {
private int portNumber;
public ServerStart(int portNumber) {
this.portNumber = portNumber;
}
public void run() {
try {
conn = getConnection();
stat = conn.createStatement();
} catch (SQLException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
serverSocket = new ServerSocket(portNumber);
} catch (IOException e) {
e.printStackTrace();
}
try {
while (true) {
Socket incoming = serverSocket.accept();
clientSockets.add(incoming);
Runnable r = new ClientCommunication(incoming);
Thread t = new Thread(r);
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Code Client:
public void actionPerformed(ActionEvent e) {
if (isConnected == false) {
String ServerIP = ip.getText().trim();
int ServerPort = Integer
.parseInt(port.getText().trim());
try {
ClientSocket = new Socket(ServerIP, ServerPort);
clientObjectInput = new ObjectInputStream(
ClientSocket.getInputStream());
clientObjectOutput = new ObjectOutputStream(
ClientSocket.getOutputStream());
isConnected = true;
} catch (IOException ex) {
}
synchronized (this) {
try {
ClientLoginFrame login = new ClientLoginFrame();
Employee employee = login.getEmployee();
clientObjectOutput.writeObject(employee);
int result = clientObjectInput.readInt();
if(result == 1)
{
// DO SOMETHING
}
else {
ClientSocket.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
});
}
add an ex.printStackTrace() to see what is happening in your
catch(IOException | ClassNotFoundException | SQLException ex)
Server side, on your ClientCommunication class: it seems you are closing the socket before entering the while loop. So the socket is already closed and cannot send/receive messages. You should NOT call incoming.close() there, but at the end of your run() method.