簡體   English   中英

Java Networking:在Socket中解釋InputStream和OutputStream

[英]Java Networking: Explain InputStream and OutputStream in Socket

我使用ServerSocket創建了一個服務器。 之后,我使用Socket創建了Client,並連接到該服務器。

之后,我使用InputStream執行“一些東西”,並從Socket Object獲取OutputStream。 但是,我真的不太了解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();
                }

結果將是:“Hello World”和“Hello StackOverFlow”。

這是服務器端代碼:

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,...一個字符串,對嗎?

套接字是一種抽象,可用於與網絡中的某些內容進行通信。 見下圖......

在Java中,要通過套接字發送數據,您將從中獲取OutputStream (1),並寫入OutputStream (您輸出一些數據)。

要從套接字讀取數據,您將獲得其InputStream ,並從此第二個流中讀取輸入。

您可以將流視為連接到牆上插座的一對單向管道。 在牆的另一邊發生的事情不是你的問題!

在您的情況下,服務器有另一個套接字(連接的另一端)和另一對流。 它使用其InputStream (2)從網絡讀取,並使用其OutputStream (3)將相同的數據通過網絡寫回客戶端,客戶端通過其InputStream (4)再次讀取它完成往返。

      Client                                                     Server

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

更新:回復評論:

請注意,流和套接字只發送原始字節; 他們在這個抽象層面上沒有“信息”的概念。 因此,如果您發送X個字節和另外X個字節,然后讀取X個字節並讀取另外X個字節,那么您的系統就像有兩個消息一樣,因為這就是您划分字節的方式。

如果發送X個字節和另外X個字節,然后讀取長度為2X的回復,那么您可能能夠讀取單個組合的“消息”,但正如您所注意到的,流的底層實現可以選擇何時到傳遞大塊的字節,因此它可能返回X字節,然后是X字節,稍后或一次2X,或0.5X四次......

InputStreamOutputStream是兩個完全獨立的流。 你寫入的內容與你從另一個中讀到的內容沒有先驗關系。 InputStream為您提供服務器決定發送給您的任何數據。 我還想評論你的代碼:

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

您使用字符串test的長度(未在代碼中顯示),這與您作為第一個參數傳遞的字節數組無關。 這可能導致ArrayIndexOutOfBoundsException或截斷您的預期消息。

對您更新的問題的其他評論

查看服務器端代碼時,編寫的代碼不正確。 你需要try { handleConnection(...); } finally { socket.close(); } try { handleConnection(...); } finally { socket.close(); } try { handleConnection(...); } finally { socket.close(); } ,以確保適當的清除錯誤之后,以及正常完成時相同。 您的代碼永遠不會關閉服務器端的任何內容。

最后,最重要的是,您的整個代碼都是以可能導致死鎖的方式編寫的。 通常,您需要一個單獨的線程來讀取和寫入; 否則可能發生以下情況:

  1. 您嘗試將一些數據寫入輸出;
  2. 服務器讀取它並嘗試響應輸入中的數據;
  3. 但是,由於緩沖區太小,您無法發送所有內容,因為服務器希望先向您發送內容,然后接收其余內容; 但是在你發送了你所有的東西之前,你沒有到達接收部分。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM