15

を使用してサーバーを作成しましたServerSocket。その後、を使用してクライアントを作成しSocket、このサーバーに接続します。

その後、InputStreamを使用して「いくつかの作業」を行い、OutputStreamはSocketObjectから取得されます。しかし、私はinputStreamとoutputStreamをあまり理解していません。これが私の簡単なコードです:

private Socket sock = null;
private InputStream sockInput = null;
private OutputStream sockOutput = null;

...
            String msg = "Hello World";
            byte[] buffer = null;

            try {
                sockOutput.write(msg.getBytes(), 0, test.length());
                sockOutput.write("Hello StackOverFlow".getBytes(), 0, test.length());
                buffer = new byte[test.length()];
                sockInput.read(buffer, 0, test.length());
                System.out.println(new String(buffer));
                sockInput.read(buffer, 0, test.length());
                System.out.println(new String(buffer));
            } catch (IOException e1) {
                e1.printStackTrace();
                }

結果は、「HelloWorld」と「HelloStackOverFlow」になります。

サーバー側のコードは次のとおりです。

private int serverPort = 0;
    private ServerSocket serverSock = null;

    public VerySimpleServer(int serverPort) {
        this.serverPort = serverPort;

        try {
            serverSock = new ServerSocket(this.serverPort);
        }
        catch (IOException e){
            e.printStackTrace(System.err);
        }
    }

    // All this method does is wait for some bytes from the
    // connection, read them, then write them back again, until the
    // socket is closed from the other side.
    public void handleConnection(InputStream sockInput, OutputStream sockOutput) {
        while(true) {
            byte[] buf=new byte[1024];
            int bytes_read = 0;
            try {
                // This call to read() will wait forever, until the
                // program on the other side either sends some data,
                // or closes the socket.
                bytes_read = sockInput.read(buf, 0, buf.length);

                // If the socket is closed, sockInput.read() will return -1.
                if(bytes_read < 0) {
                    System.err.println("Server: Tried to read from socket, read() returned < 0,  Closing socket.");
                    return;
                }
                System.err.println("Server: Received "+bytes_read
                                   +" bytes, sending them back to client, data="
                                   +(new String(buf, 0, bytes_read)));
                sockOutput.write(buf, 0, bytes_read);
                // This call to flush() is optional - we're saying go
                // ahead and send the data now instead of buffering
                // it.
                sockOutput.flush();
            }
            catch (Exception e){
                System.err.println("Exception reading from/writing to socket, e="+e);
                e.printStackTrace(System.err);
                return;
            }
        }

    }

    public void waitForConnections() {
        Socket sock = null;
        InputStream sockInput = null;
        OutputStream sockOutput = null;
        while (true) {
            try {
                // This method call, accept(), blocks and waits
                // (forever if necessary) until some other program
                // opens a socket connection to our server.  When some
                // other program opens a connection to our server,
                // accept() creates a new socket to represent that
                // connection and returns.
                sock = serverSock.accept();
                System.err.println("Server : Have accepted new socket.");

                // From this point on, no new socket connections can
                // be made to our server until we call accept() again.

                sockInput = sock.getInputStream();
                sockOutput = sock.getOutputStream();
            }
            catch (IOException e){
                e.printStackTrace(System.err);
            }

            // Do something with the socket - read bytes from the
            // socket and write them back to the socket until the
            // other side closes the connection.
            handleConnection(sockInput, sockOutput);

            // Now we close the socket.
            try {
                System.err.println("Closing socket.");
                sock.close();
            }
            catch (Exception e){
                System.err.println("Exception while closing socket.");
                e.printStackTrace(System.err);
            }

            System.err.println("Finished with socket, waiting for next connection.");
        }
    }

    public static void main(String argv[]) {
        int port = 54321;
        VerySimpleServer server = new VerySimpleServer(port);
        server.waitForConnections();
    }

私の質問は:

  1. を使用するsockOutput.writeと、これらのメッセージを。で取り戻すことができますsockInput.read。それで、それらのメッセージは保存されましたね?これが当てはまる場合、私が作成したサーバーに保存されていますか、それとも。などの他のものに保存されていますかSocket Object

  2. ソケット文字列A1、A2、...に書き込んだ場合、それぞれA1、A2、...文字列を受け取りますよね?

4

2 に答える 2

40

ソケットは、ネットワークを介して何かと通信するために使用する抽象化です。下の図を参照してください...

Javaでは、ソケットを介してデータを送信するには、ソケットOutputStreamから(1)を取得し、に書き込みOutputStreamます(データを出力します)。

ソケットからデータを読み取るには、ソケットを取得しInputStream、この2番目のストリームから入力を読み取ります。

ストリームは、壁のソケットに接続された1対の一方通行パイプと考えることができます。壁の向こう側で何が起こっているかはあなたの問題ではありません!

あなたの場合、サーバーには別のソケット(接続のもう一方の端)と別のストリームのペアがあります。(2)を使用しInputStreamてネットワークから読み取り、OutputStream(3)を使用して同じデータをネットワーク経由でクライアントに書き戻し、クライアントはInputStream(4)ラウンドトリップを完了して再度読み取ります。

      Client                                                     Server

1. OutputStream -->\                                     /--> 2. InputStream -->
                    Socket <--> network <--> ServerSocket                       |
4. InputStream  <--/                                     \<--3. OutputStream <--

更新:コメントへの返信:

ストリームとソケットは生のバイトを送信するだけであることに注意してください。このレベルの抽象化では、「メッセージ」の概念はありません。したがって、Xバイトと別のXバイトを送信し、次にXバイトを読み取り、別のXバイトを読み取ると、システムは2つのメッセージがあるかのように動作します。これは、バイトを分割した方法だからです。

Xバイトと別のXバイトを送信し、長さ2Xの応答を読み取ると、単一の結合された「メッセージ」を読み取ることができる場合がありますが、お気づきのとおり、ストリームの基盤となる実装はバイトのチャンクを配信するため、Xバイト、次にXバイト、後で、または一度に2X、または0.5Xを4回返す可能性があります...

于 2012-10-03T19:49:05.927 に答える
5

InputStreamOutputStreamは2つの完全に別個のストリームです。あなたが一方に書いたものは、あなたがもう一方から読んだものと先験的な関係はありません。InputStream、サーバーが送信することを決定したデータを提供します。また、あなたのコードのこの部分についてコメントしたいと思います。

sockOutput.write(msg.getBytes(), 0, test.length());
sockOutput.write("Hello StackOverFlow".getBytes(), 0, test.length());

文字列の長さtest(コードには表示されていません)を使用します。これは、最初の引数として渡すバイト配列とは関係ありません。これArrayIndexOutOfBoundsExceptionにより、意図したメッセージが切り捨てられる可能性があります。

更新された質問への追加コメント

サーバー側のコードを確認すると、正しく記述されていません。try { handleConnection(...); } finally { socket.close(); }エラー後、および正常に完了した場合は、適切なクリーンアップを確保する必要があります。コードがサーバー側で何かを閉じることはありません。

最後に、そして最も重要なこととして、コード全体がデッドロックを引き起こす可能性のある方法で記述されています。通常、読み取りと書き込みには別々のスレッドが必要です。そうしないと、次のことが発生する可能性があります。

  1. 出力にデータを書き込もうとしました。
  2. サーバーはそれを読み取り、入力のデータで応答しようとします。
  3. ただし、バッファが小さすぎるため、サーバーが最初に何かを送信してから残りを受信するため、すべてを送信することはできません。しかし、持っているものをすべて送信する前に、受信部分に到達することはありません。
于 2012-10-03T19:25:07.147 に答える