15

我通过使用创建了一个服务器ServerSocket。之后,我使用创建了客户端Socket,并连接到该服务器。

之后,我用 InputStream 做“一些事情”,OutputStream 取自 Socket 对象。但是,我不太了解 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. 如果我已写入套接字 String A1, A2,... An 那么我将分别收到 A1, A2, ... An String,对吗?

4

2 回答 2

40

套接字是一种抽象,您可以使用它通过网络与某些东西进行通信。见下图...

在 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 四次......

于 2012-10-03T19:49:05.927 回答
5

InputStream并且OutputStream是两个完全独立的流。您写入其中的内容与您从另一个中读取的内容没有先验关系。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 回答