20

I am new to Socket programming in Java and was trying to understand if the below code is not a wrong thing to do. My question is:

Can I have multiple clients on each thread trying to connect to a server instance in the same program and expect the server to read and write data with isolation between clients"

public class Client extends Thread
{
    ...
    void run()
    {
        Socket socket = new Socket("localhost", 1234);
        doIO(socket);  
    }
}

public class Server extends Thread
{
    ...
    void run()
    {
        // serverSocket on "localhost", 1234
        Socket clientSock = serverSocket.accept();
        executor.execute(new ClientWorker(clientSock));
    }
}

Now can I have multiple Client instances on different threads trying to connect on the same port of the current machine?

For example,

   Server s = new Server("localhost", 1234);
   s.start();
   Client[] c = new Client[10];
   for (int i = 0; i < c.length; ++i)
   {
        c.start();
   }
espcorrupt
  • 201
  • 1
  • 2
  • 3

6 Answers6

11

Yes, however only one client will be able to connect per thread execution as written.

You can just put your server run() inside a while true loop to let multiple clients connect. Depending on the executor, they will execute either in series or parallel.

   public class Server extends Thread  
   {  
       ...  
       void run()  
       {  
           while(true){
              // serverSocket on "localhost", 1234  
              Socket clientSock = serverSocket.accept();  
              executor.execute(new ClientWorker(clientSock));  
           }
       }  
   } 
patros
  • 7,719
  • 3
  • 28
  • 37
4

As long as you only have one object trying to bind the port for listening, then there's no problem with multiple clients connecting.

Jherico
  • 28,584
  • 8
  • 61
  • 87
  • Thanks guys, I thought of the port as a single physical entity (like a wire) since it has a single number. So my thinking was it can be used by only one client socket, otherwise multiple client sockets could write into the same wire at a time. But from your answers, I think the port itself is made of multiple resources (say, like memory blocks) but the socket will be bound to one of those blocks probably indexed by some binding key. – espcorrupt May 13 '10 at 04:16
  • 5
    The port is just a number. It doesn't correspond to anything physical. A *connection* is defined by the tuple {protocol, source address, source port, target address, target port}. The client-side OS will take care of ensuring different outbound port numbers for each outgoing connection. So there is no problem in having multiple inbound connections to the same target host/port, even if they are all from the same client source host. – user207421 May 13 '10 at 10:16
1

In this example, your Server accepts and handles one client connection at a time. You can have as many Clients as you want attempting to connect, but only one at a time will be handled.

It is not apparent whether your executor logic is multithreaded, since you didn't provide the implementation. If the executor delegates to a threadpool or something like that, you would need to make sure that your ClientWorker is thread-safe, as you will have multiple instances executing in parallel.

I am of course assuming that your Client is thread-safe as well, since your question is only concerning the Server.

danben
  • 80,905
  • 18
  • 123
  • 145
0

Yes, it doesn't matter whether your clients are local or remote. The important thing in your example is that ClientWorker is thread-safe, as your server will have multiple instances of that class (one for each client connection).

G__
  • 7,003
  • 5
  • 36
  • 54
0

So. To begin:

You can accept more clients with one serversocket, because you accept only one in the run-method. You have just to call accept() a second time.

Then, you in your for loop: first you have to create each time a new Client object. Then you can call c[i].start(); and not c.start().

Now can I have multiple Client instances on different threads trying to connect on the same port of the current machine?

Yes you can. Just create new Threads and run them. This should work perfectly.

expect the server to read and write data with isolation between clients

You can use your experience of the basic IO techniques like with file-io:

OutputStream os = socket.getOutputStream();
PrintStream pw = new PrintStream(os, true); // Or PrintWriter, I don't know what the best one is.
pw.println("Hello, other side of the connection!");

And for reading use a BufferedReader.

Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
0

You can try something on these lines

public class MultiThreadServer extends Application {
  // Text area for displaying contents
  private TextArea ta = new TextArea();

  // Number a client
  private int clientNo = 0;

  @Override // Override the start method in the Application class
  public void start(Stage primaryStage) {
    // Create a scene and place it in the stage
    Scene scene = new Scene(new ScrollPane(ta), 450, 200);
    primaryStage.setTitle("MultiThreadServer"); // Set the stage title
    primaryStage.setScene(scene); // Place the scene in the stage
    primaryStage.show(); // Display the stage

    new Thread( () -> {
      try {
        // Create a server socket
        ServerSocket serverSocket = new ServerSocket(8000);
        ta.appendText("MultiThreadServer started at " 
          + new Date() + '\n');

        while (true) {
          // Listen for a new connection request
          Socket socket = serverSocket.accept();

          // Increment clientNo
          clientNo++;

          Platform.runLater( () -> {
            // Display the client number
            ta.appendText("Starting thread for client " + clientNo +
              " at " + new Date() + '\n');

            // Find the client's host name, and IP address
            InetAddress inetAddress = socket.getInetAddress();
            ta.appendText("Client " + clientNo + "'s host name is "
              + inetAddress.getHostName() + "\n");
            ta.appendText("Client " + clientNo + "'s IP Address is "
              + inetAddress.getHostAddress() + "\n");
          });

          // Create and start a new thread for the connection
          new Thread(new HandleAClient(socket)).start();
        }
      }
      catch(IOException ex) {
        System.err.println(ex);
      }
    }).start();
  }

  // Define the thread class for handling new connection
  class HandleAClient implements Runnable {
    private Socket socket; // A connected socket

    /** Construct a thread */
    public HandleAClient(Socket socket) {
      this.socket = socket;
    }

    /** Run a thread */
    public void run() {
      try {
        // Create data input and output streams
        DataInputStream inputFromClient = new DataInputStream(
          socket.getInputStream());
        DataOutputStream outputToClient = new DataOutputStream(
          socket.getOutputStream());

        // Continuously serve the client
        while (true) {
          // Receive radius from the client
          double radius = inputFromClient.readDouble();

          // Compute area
          double area = radius * radius * Math.PI;

          // Send area back to the client
          outputToClient.writeDouble(area);

          Platform.runLater(() -> {
            ta.appendText("radius received from client: " +
              radius + '\n');
            ta.appendText("Area found: " + area + '\n');
          });
        }
      }
      catch(IOException e) {
        ex.printStackTrace();
      }
    }
  }

  /**
   * The main method is only needed for the IDE with limited
   * JavaFX support. Not needed for running from the command line.
   */
  public static void main(String[] args) {
    launch(args);
  }
}
Kashif
  • 1