1

私は、サーバーがメッセージをクライアントにエコーバックするTCPクライアントとサーバーを期待するプロジェクトに取り組んでいます。以下は、割り当てからです。

サーバー アプリケーションは、次のことを行う必要があります。

  1. 既知の IP アドレスとポートで TCP 接続をリッスンする
  2. そのポートで開始された接続を受け入れる
  3. クライアントからメッセージを受信し、エコー バックする
  4. クライアントが接続を切断するまで、これを続けます。

クライアント アプリケーションは、次のことを行う必要があります。

  1. 既知の IP アドレスとポートでサーバーとの接続を確立する
  2. メッセージを非同期でサーバーに送信します。メッセージの形式は任意です。ただし、サーバーから返されたときに認識されるように、十分な情報が含まれている必要があります。

サーバー用のコーディングを完了しました。これがクライアント用に思いついたものです。

私の質問:

  • サーバーがよく知られている IP とポートで TCP 接続をリッスンするとはどういう意味ですか? 私の実装でServerSocketは、サーバーがリッスンするポートを受け入れるものを使用しました。私はそれを正しく解釈しましたか?

  • 私の現在の TCPClient の実装では、クライアントはサーバーにメッセージを送信しますが、println() はブロッキング呼び出しのようであり、同期になります。クライアントを非同期にするにはどうすればよいですか?

簡潔にするために、TCPServer のコードを追加していません。必要な場合はお知らせください。

更新* * フィードバックに基づいて、TCPClient クラスで変更しました。クライアント要求を受け取った後、ReceiveMessage と SendMessage の 2 つのスレッドを生成します。それを行うと、次の例外が発生します。

[Client] Message sent: Message from Client 97
[Client] Message sent: Message from Client 98
[Client] Message sent: Message from Client 99
[Client] Done Sending all the messages
java.net.SocketException: Socket closed
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:129)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
    at java.io.InputStreamReader.read(InputStreamReader.java:167)
    at java.io.BufferedReader.fill(BufferedReader.java:136)
    at java.io.BufferedReader.readLine(BufferedReader.java:299)
    at java.io.BufferedReader.readLine(BufferedReader.java:362)
    at org.chanders.client.ReceiveMessage.run(ReceiveMessage.java:18)
    at java.lang.Thread.run(Thread.java:680)

以下は、新しいクライアント コードです。

public class TCPClient {
    Socket clientSocket = null;
    OutputStream out = null;
    BufferedReader in = null;
    String message = "Hello from Client";
    int messagecount = 100;

    // server credentials
    private static final String SERVER_ADDRESS = "localhost";
    private static final int SERVER_PORT = 50001;

    protected void execute() {
        try {
            clientSocket = new Socket(SERVER_ADDRESS, SERVER_PORT);
            Thread send = new Thread(new SendMessage(clientSocket.getOutputStream()));
            Thread receive = new Thread(new ReceiveMessage(clientSocket.getInputStream()));

            send.start();
            receive.start();

            //For server to wait until send and receive threads finish
            send.join();
            receive.join();

        } catch (UnknownHostException uhe) {
            System.err.println("Couldnt find host:  "  + SERVER_ADDRESS);
            uhe.printStackTrace();
            System.exit(-1);

        }catch(IOException ioe) {
            System.err.println("Couldnt get I/O:  "  + SERVER_ADDRESS);
            ioe.printStackTrace();
            System.exit(-1);

        }catch(InterruptedException ie) {
            System.err.println("Thread.join failed:  ");
            ie.printStackTrace();
            System.exit(-1);
        }
        finally {
            //cleanup();
        }
    }

    private void cleanup() {
        try {
            clientSocket.close();
        }catch(Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }
    }

    public static void main(String[] args) {
        TCPClient client = new TCPClient();
        client.execute();
    }

public class SendMessage implements Runnable {
    OutputStream out = null;
    String message = "Message from Client";
    int messageCount = 100;

    public SendMessage(OutputStream out) {
        this.out = out;
    }

    public void run() {
        PrintWriter writer = new PrintWriter(out);
        try {

            for (int i = 0; i < messageCount; i++) {
                String m = message + " " + i;
                writer.println(m);
                System.out.println("[Client] Message sent: " + m);
            }
            System.out.println("[Client] Done Sending all the messages");

        } catch (Exception e) {
            e.printStackTrace();
            System.exit(-1);
        } finally {
            cleanup();
        }

    }
    private void cleanup() {
        try {
            out.close();
        }catch(Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }
    }
}

public class ReceiveMessage implements Runnable {
    InputStream in = null;
    String message;

    public ReceiveMessage(InputStream in) {
        this.in = in;
    }

    public void run() {
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        try {

            while ((message = reader.readLine()) != null) {

                System.out.println("[Client] Received message from Server: "
                        + message);
            }

            System.out.println("[Client] Done Receiving messages from Server");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            cleanup();
        }

    }
    private void cleanup() {
        try {
            in.close();
        }catch(Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }
    }
}
4

4 に答える 4

1

このコンテキストでは、Asynchronousおそらく println を使用できないという意味ではなく、クライアントが新しいメッセージを送信している間にメッセージを受信できなければならないということです。クライアントはソケットを作成し、2 つのスレッドを作成する必要があります。1 つはメッセージを送信するスレッドで、もう 1 つはメッセージを受信して​​印刷するスレッドです。

アップデート

例外を回避するには、出力ストリームを閉じる代わりに clientSocket.shutdownOutput() を使用します。送信コードをメイン スレッドに戻し、受信コード用に別のスレッドを保持するか、送信スレッドに参加した後に shutdownOutput() を呼び出すことができます。あなたにとってより良いものは何でも。

于 2012-08-30T19:59:42.963 に答える
0

これが(宿題ではなく)専門的な仕事である場合は、基本的にNIOクライアントサーバーフレームワークであるNettyサーバーを強くお勧めします。これにより、この種の開発が大幅に簡素化/合理化されます。

質問に記載されているサーバー/クライアント機能を正確に実装する例が記載されているので、必ずドキュメントを確認してください。

これが宿題の場合、この例は必要なすべての詳細を提供する必要があります。Oracleリソースも確認してください。

于 2012-08-30T20:25:58.013 に答える
0

よく知られているポートは、特定のプロトコル用に特別に指定されたポート番号です。たとえば、80はHTTP用、443はHTTPS用です。特定のプロトコルを実装するつもりですか?もしそうなら、そのプロトコルのポート番号を使用することをお勧めします。ウィキペディアには、よく知られているポート番号のリストがあります:http: //en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers

于 2012-08-30T20:15:28.803 に答える
0

クライアントごとに個別のスレッドを使用します。あなたが何かを書くとき、サーバー側で、文字列を受け入れるメソッドがなければなりません。そうしないと、ブロックされます。サーバー コードを貼り付けます。

于 2012-08-30T19:55:07.490 に答える