20

私は Java での Socket プログラミングは初めてで、以下のコードが間違っているかどうかを理解しようとしていました。私の質問は:

同じプログラム内のサーバー インスタンスに接続しようとする各スレッドに複数のクライアントを配置し、サーバーがクライアント間で分離してデータの読み取りと書き込みを行うことを期待できますか?」

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

現在のマシンの同じポートに接続しようとしている異なるスレッドに複数の Client インスタンスを配置できますか?

例えば、

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

6 に答える 6

11

はい、ただし、記述されているように、スレッド実行ごとに接続できるクライアントは 1 つだけです。

サーバーの run() を while true ループ内に配置するだけで、複数のクライアントを接続できます。エグゼキュータに応じて、直列または並列で実行されます。

   public class Server extends Thread  
   {  
       ...  
       void run()  
       {  
           while(true){
              // serverSocket on "localhost", 1234  
              Socket clientSock = serverSocket.accept();  
              executor.execute(new ClientWorker(clientSock));  
           }
       }  
   } 
于 2010-05-12T18:36:57.997 に答える
4

ポートをリッスンするためにバインドしようとしているオブジェクトが 1 つしかない限り、複数のクライアントが接続しても問題はありません。

于 2010-05-12T18:30:00.600 に答える
1

この例でServerは、一度に 1 つのクライアント接続を受け入れて処理します。はいくつでもClient接続を試みることができますが、一度に処理されるのは 1 つだけです。

実装を提供していないため、executor ロジックがマルチスレッド化されているかどうかは明らかではありません。ClientWorkerエグゼキューターがスレッドプールなどに委任する場合、複数のインスタンスが並行して実行されるため、スレッドセーフであることを確認する必要があります。

もちろんClient、あなたの質問はServer.

于 2010-05-12T18:33:33.537 に答える
0

はい、クライアントがローカルかリモートかは関係ありません。あなたの例で重要なことは、サーバーにはそのクラスの複数のインスタンス(クライアント接続ごとに1つ)があるため、ClientWorkerがスレッドセーフであることです。

于 2010-05-12T18:33:05.383 に答える
0

そう。始める:

-methodでは 1 つしか受け入れないため、1 つのサーバーソケットでより多くのクライアントを受け入れることができますrun。もう一度電話accept()するだけです。

次に、 for ループで: 最初に毎回新しいClientオブジェクトを作成する必要があります。c[i].start();その後、呼び出すことができますc.start()

現在のマシンの同じポートに接続しようとしている異なるスレッドに複数の Client インスタンスを配置できますか?

はい、できます。新しいスレッドを作成して実行するだけです。これは完全に機能するはずです。

サーバーがクライアント間で分離してデータを読み書きすることを期待する

file-io などの基本的な 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 を使用します。

于 2010-05-12T18:37:41.583 に答える
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);
  }
}
于 2017-10-04T12:18:18.743 に答える