0

I'm doing a little client/server app. For now it's functioning well, but I need to add an "option".

The server class is like this:

public class Server {

    public static void main(String[] zero) throws IOException {

        ServerSocket serverSocket  ;
        Socket clientSocket ;

        DataBase DB = new DataBase();
        System.out.println("ouverture du server");
        serverSocket = new ServerSocket(2000);

        DB.printAll(); //just to see the DB.


        while(true) { 
            try {

                clientSocket = serverSocket.accept(); 
                Thread t = new Thread(new Connect(clientSocket, DB));
                t.start();

            }catch (IOException e) {
                e.printStackTrace();
            }       
        }
    }
}

So a lot of clients are able to connect to the server. My point is: I want a connected client (say, Client1) to be able to send something to another connected client (Client2) of his choice.

And my problem: how can Client1 find/have/retrieve the socket of Client2, since all client connect to the server through this clientSocket in different threads?

I've read this which propose to make a list of dataoutputstream containing the outputStream of each connected client. This seem like a good idea, but I would prefer to do the same with sockets (because I'm not sure if I'll need the "data" output stream or another output stream for now, and in any case it'll be more clear for me with the sockets).

Plus, Client2 is doing his own stuff with the server, which includes exchange data, so he'll use his output/input stream. I have to make sure that this won't mix up.

For example, say Client2 send something to server and wait a response. Then Client1 send something to Client2; instead of the server response, Client2 receive what Client1 send; as he wasn't suppose to receive that, this lead to fatal error.

I've read something about synchronized threads, it seems to be what I need, but I'm new to java and this is a bit hard?

I think if I declare the Client2 Socket as synchronized, then the thread will wait until clientSocket is free before using it; and since the client isn't supposed to disconnect (and if he does, well the socket is closed so we can't send him anything), the thread (of client1) won't be able to use the socket of client2.

Now, if I synchronize the DataOutputStream, sometimes communication between client2 and server involves many different outputstream, so the DataOutputStream can be free to use, but the Client2 will still be waiting for an input from server, not from Client1, so not the same input.

Maybe I can synchronise directly the complete OutputStream. Or maybe what I said just doesn't have any sense. Help?

6
  • 1
    Your question is far to broad, and you seem to be confused about what is possible: client 1 will not be able to use the socket from the server to client 2, as they are different applications and therefor don't share the socket. You will need to design and implement some form of async protocol for message exchange between clients through the server. Commented Aug 2, 2018 at 9:28
  • Not the best question but why don't you use already existing technologies? Commented Aug 2, 2018 at 9:40
  • @MarkRotteveel maybe i didn't explain that well: client1 went to send something to client2 via the server; so he sends it to the server, and the server send it to client2. if i had client1Socket and client2Socket it would be easy, but i just have clientSocket and a thread. How can the server retrieve the socket of a connected Client when we're in the "runnable part" of another? All clients are authentified when they connect, so they have an username, which is saved in DB. Can i save the clientSocket in DB too? Commented Aug 2, 2018 at 10:12
  • @dorintufar if there is already java code doing that, i'll happily use it. i just didn't found it. If you mean an app, the point of my work is to create one (who doesn't already exist of course, if not it wouldn't have any sense), and it's doing more than what i said here. Commented Aug 2, 2018 at 10:13
  • Your question is not trivial and in my opinion far too broad to be suitable for Stack Overflow. Commented Aug 2, 2018 at 10:27

1 Answer 1

1

Well, since i posted it i guess i can aswer it too.

So, it's not a perfect solution (in my opinion) and i'm not totally done with it, but it seems to work so far.

For the first problem (how to retrieve another client Socket), i'm creating a static hashtable on server side, with the client name as key and the socket as value. Whenever a client connect, he's added to this table; and when he disconnects he's deleted (i didn't try the disconnect part)

private static Hashtable<String,Socket> connectedClients= new Hashtable<String, Socket>();
public static void setConnectedClient(String username, Socket clientSocket) {
    connectedClients.put(username, clientSocket);
}

public static void disconnectClient(String user) {
    connectedClients.remove(user);
}

So wherever i am in the program on server side, i can retrieve a client socket (knowing his username).

For the second problem (how to avoid mixup witht he other client work with the server) i'm creating a second socket. Which mean, on client side there's two socket: one for communication with server, and one for communication with clients (coming from the server) on another port. Which mean i also have another server socket on server side for this other port. So, when a client connect to the server, this second socket is created on client & server side.

        Socket TCHATSocket = Server.getServerSocket().accept(); //create a new socket specifically for TCHAT
        Server.setConnectedClient(user, TCHATSocket); //register the client ID & TchatSocket in the list of connected clients.

Now, on client side i must keep listening for any input from this socket (in case another client want to communicate with me through the server) but not when i'm doing stuff with the server.

To do that, i create another thread on client side. When the client connect, it launch the thread which create the second socket and wait for an input from the server. But, when the client launch any function which involve communication with server, this thread is paused, and then unpaused at the end of the function. Here is the thread class:

package client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class TCHAT extends Thread{
    private InputStream in;
    private OutputStream out;
    private Socket pakeSocket;
    private String message;
    private volatile boolean pause = false;

    public void pause() {
        pause = true;
    }

    public void unPause() {
        pause = false;
        synchronized(this) {
            notify();
        }

    }

    public TCHAT() {
        try {
            tchatSocket = new Socket(InetAddress.getLocalHost(),2004);
            in = tchatSocket.getInputStream();
            out = tchatSocket.getOutputStream();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void run(){
        while(!tchatSocket.isClosed()) {

            if(pause) {
                System.out.println("TCHAT paused");
                synchronized (this) {
                    try {
                        wait();// wait until someone calls notify() (by calling the method unPause)
                    }catch (InterruptedException e) {           
                        e.printStackTrace();            
                    }
                }
            }

            else {
                System.out.println("Waiting for TCHAT demand");
                try {
                    BufferedReader br = new BufferedReader(new InputStreamReader(in));
                    message = br.readLine();
                    System.out.println(message);
                    //Find a way to blok the while after receiving the message:
                    tchatSocket.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }


        }
    }

}

As you can see, it's not really terminated: for now i just get a message from server and then close the socket; but i guess you can do whatever you want before closing it. Plus, for some reason, i never get the "TCHAT paused" message when i call pause(), and i don't get another "Waiting for TCHAT demand" when i unpause, but it seems to work (since without the pause the others clients functions won't work, and here they work well, and the client correctly receive the message from server even after uploading or whatever.)

basically, when i want to use a client function, i just do:

TCHAT.pause();
upload(file); //or any function involving client/server communication
TCHAT.unpause();

Hope it'll help someone, but still happy to make it work :)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.