2010-05-12 3 views
15

Я новичок в программировании сокетов на Java и пытался понять, не подходит ли этот код ниже. Мой вопрос:Сокеты Java: несколько потоков клиентов на одном и том же порту на одном компьютере?

Могу ли я иметь несколько клиентов на каждом потоке пытается подключиться к экземпляру сервера в той же программе и ожидать, что сервер для чтения и записи данных с изоляцией между клиентами»

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)); 
    } 
} 

Теперь можно у меня есть несколько экземпляров клиента на разных потоках, пытающихся подключиться на тот же порт текущей машины?

Например,

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

ответ

3

Пока у вас есть только один объект, пытающийся связать порт для прослушивания, тогда нет проблем с подключением нескольких клиентов.

+0

Спасибо, ребята, я думал порта как одного физического лица (например, провода), поскольку она имеет единственное число. Поэтому я думал, что он может использоваться только одним клиентским сокетом, иначе несколько клиентских сокетов могут записываться в один и тот же провод за раз. Но из ваших ответов я думаю, что сам порт состоит из нескольких ресурсов (например, как блоки памяти), но сокет будет привязан к одному из тех блоков, которые, вероятно, индексируются некоторым ключом привязки. – espcorrupt

+3

Порт - это просто номер. Это не соответствует чему-либо физическому. A * connection * определяется кортежем {протокол, адрес источника, порт источника, адрес цели, целевой порт}. Клиентская ОС позаботится об обеспечении разных номеров исходящих портов для каждого исходящего соединения. Таким образом, нет никаких проблем при наличии нескольких входящих соединений с одним и тем же целевым хостом/портом, даже если они все находятся на одном и том же узле исходного клиента. – EJP

0

Да, неважно, являются ли ваши клиенты локальными или удаленными. В вашем примере важно, чтобы ClientWorker был потокобезопасным, так как ваш сервер будет иметь несколько экземпляров этого класса (по одному для каждого клиентского соединения).

1

В этом примере ваш Server принимает и обрабатывает одно клиентское соединение за раз. У вас может быть столько Client, сколько вы хотите подключиться, но будет обработано только по одному.

Неясно, является ли ваша логика исполнителя многопоточной, поскольку вы не обеспечили реализацию. Если исполнитель делегирует threadpool или что-то подобное, вам нужно убедиться, что ваш ClientWorker является потокобезопасным, так как вы будете иметь несколько экземпляров, выполняемых параллельно.

Я, конечно, предполагаю, что ваш Client также потокобезопасен, так как ваш вопрос касается только Server.

8

Да, однако только один клиент сможет подключиться к исполнению потока, как указано.

Вы можете просто запустить ваш сервер run() внутри цикла while, чтобы позволить нескольким клиентам подключиться. В зависимости от исполнителя они будут выполняться последовательно или параллельно.

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

So. Для начала:

Вы можете принять больше клиентов с одним сервером, потому что вы принимаете только один из методов run. Вы должны просто позвонить accept() во второй раз.

Затем вы в своем цикле for: сначала вы должны создавать каждый раз новый объект Client. Затем вы можете позвонить c[i].start();, а не c.start().

Теперь я могу иметь несколько клиентских экземпляров на разных потоках, пытающихся соединить на тот же порт текущей машины?

Да, вы можете. Просто создайте новые темы и запустите их. Это должно работать отлично.

ожидать сервер для чтения и записи данных с изоляцией между клиентами

Вы можете использовать свой опыт основных методов ввода-вывода, как с файлом-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!"); 

И для чтение используется BufferedReader.

0

Вы можете попробовать что-то на этих линиях

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); 
    } 
} 
Смежные вопросы