I am trying to implement a peer to peer chat system using java for some university homework. Each node consists of a server and a client the server receives the message and the client sends the messages. When you set a new port for your node The following function is called :
private void setServer(int port) {
try {
serverSocket = new ServerSocket(port);
new Thread(() -> {
while (!serverSocket.isClosed()) {
try {
Socket socket = serverSocket.accept();
addNumberOfConnections(1);
startNewConnection(socket);
addNumberOfConnections(-1);
} catch (IOException ignored) {}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
Where numberOfConnections is some variable that is set to save how many people send a message but it was not properly received by the server. and the add function is implemented synchronized as follows:
public synchronized void addNumberOfConnections(int num) {
numberOfConnections += num;
}
And the start new connection is a function as follows :
public void startNewConnection(Socket socket) {
try {
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
String message = dataInputStream.readUTF();
addMessage(message);
dataInputStream.close();
socket.close();
System.err.println(messages.size());
} catch (IOException e) {
e.printStackTrace();
}
}
and add message function is also implemented synchronized as follows :
private synchronized void addMessage(String message) {
messages.add(message);
senders.add(Utils.ExtractMessage(message).getKey());
}
I use the number of the connections to make all the messages completely land before reading any data using the following function :
private void waitUntilEnds() {
while (numberOfConnections != 0) {
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Finally I send a message using the following function :
private void globalMessage(String message, String host, int port) {
try {
Socket socket = new Socket(host, port);
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
Utils.sendMessage(dataOutputStream, Utils.putInNetworkFormat(message, Main.getUser()));
dataOutputStream.close();
socket.close();
System.out.println("success");
} catch (IOException | IllegalArgumentException e) {
System.out.println("could not send message");
}
}
The problem is although I am using TCP prothocol sometimes I am not receiveing all the messages. And even more surprising some time I receive all the messages but I can't reading them all besides of calling the function waitUntil end in the beginning. More specificly I am trying to give the following input(test case) to my program :
userconfig --create --username bean --password qwerty123trewq
userconfig --login --username bean --password qwerty123trewq
portconfig --listen --port 17091
focus --start --host 127.0.0.1
send --message "This is it" --port 17091 --host 127.0.0.1
send --message "It just works" --port 17091
portconfig --listen --port 17097 --rebind
focus --port 17097
send --message "I'm calling thou"
focus --stop
send --message "General Kenobi!" --port 17097
send --message "Are you there?" --port 17097 --host 127.0.0.1
portconfig --close --port 17097
show --count --messages
show --messages
show --count --senders
portconfig --listen --port 17071
focus --start --host 127.0.0.1 --port 17071
send --message "Okay I'm back"
send --message "Are you still there?" --port 17071 --host 127.0.0.1
send --message "Ight imma head out, bye!" --port 17071
show --messages
show --senders
focus is nothing but when you do it will be the default host or port of the node where you want to send your message. giving the program this input multiple times about one time in every 5 times it receives all the messages but don't show them all and one time in every 10 times it doesn't receive the messages which are sent after rebinding. I think I have synchronized anything that was needed ( The bug cannot be in logic since it gives correct output most of the times). And ideas on what's going on?
Edit: here is the github repository of the program. I am using annotation to parse commands the main logic is in the classes Server, Client and Send Message;