# 读取和写入套接字

> 原文： [https://docs.oracle.com/javase/tutorial/networking/sockets/readingWriting.html](https://docs.oracle.com/javase/tutorial/networking/sockets/readingWriting.html)

让我们看一个简单的例子，说明程序如何使用`Socket`类建立与服务器程序的连接，然后，客户端如何通过套接字向服务器发送数据和从服务器接收数据。

示例程序实现了一个连接到 echo 服务器的客户端 [`EchoClient`](examples/EchoClient.java) 。 echo 服务器从其客户端接收数据并将其回送。示例 [`EchoServer`](examples/EchoServer.java) 实现了一个 echo 服务器。 （或者，客户端可以连接到支持[回声协议](http://tools.ietf.org/html/rfc862)的任何主机。）

`EchoClient`示例创建一个套接字，从而获得与 echo 服务器的连接。它在标准输入流上读取用户的输入，然后通过将文本写入套接字将该文本转发到 echo 服务器。服务器通过套接字将输入回送给客户端。客户端程序读取并显示从服务器传回给它的数据。

请注意，`EchoClient`示例写入和读取其套接字，从而向 echo 服务器发送数据和从 echo 服务器接收数据。

让我们来看看程序并研究有趣的部分。 `EchoClient`示例中 [`try` -with-resources](../../essential/exceptions/tryResourceClose.html) 语句中的以下语句至关重要。这些行在客户端和服务器之间建立套接字连接，并在套接字上打开 [`PrintWriter`](https://docs.oracle.com/javase/8/docs/api/java/io/PrintWriter.html) 和 [`BufferedReader`](https://docs.oracle.com/javase/8/docs/api/java/io/BufferedReader.html) ：

```
String hostName = args[0];
int portNumber = Integer.parseInt(args[1]);

try (
    Socket echoSocket = new Socket(hostName, portNumber);
    PrintWriter out =
        new PrintWriter(echoSocket.getOutputStream(), true);
    BufferedReader in =
        new BufferedReader(
            new InputStreamReader(echoSocket.getInputStream()));
    BufferedReader stdIn =
        new BufferedReader(
            new InputStreamReader(System.in))
)

```

`try` -with 资源语句中的第一个语句创建一个新的 [`Socket`](https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html) 对象并将其命名为`echoSocket`。此处使用的`Socket`构造函数需要计算机的名称和要连接的端口号。示例程序使用第一个[命令行参数](../../essential/environment/cmdLineArgs.html)作为计算机名称（主机名），使用第二个命令行参数作为端口号。在计算机上运行此程序时，请确保您使用的主机名是要连接的计算机的完全限定 IP 名称。例如，如果您的 echo 服务器正在计算机`echoserver.example.com`上运行并且正在侦听端口号 7，那么如果要将`EchoServer`示例用作 echo 服务器，请首先从计算机`echoserver.example.com`运行以下命令：

```
java EchoServer 7

```

然后，使用以下命令运行`EchoClient`示例：

```
java EchoClient echoserver.example.com 7

```

`try` -with resources 语句中的第二个语句获取套接字的输出流并在其上打开`PrintWriter`。类似地，第三个语句获取套接字的输入流并在其上打开`BufferedReader`。该示例使用读取器和写入器，以便它可以在套接字上写入 Unicode 字符。

要通过套接字将数据发送到服务器，`EchoClient`示例需要写入`PrintWriter`。要获取服务器的响应，`EchoClient`从`BufferedReader`对象`stdIn`读取，该对象在`try` -with 资源语句的第四个语句中创建。如果您还不熟悉 Java 平台的 I / O 类，您可能希望阅读 [Basic I / O](../../essential/io/index.html) 。

该程序的下一个有趣部分是`while`循环。循环从标准输入流一次读取一行，并通过将其写入连接到套接字的`PrintWriter`立即将其发送到服务器：

```
String userInput;
while ((userInput = stdIn.readLine()) != null) {
    out.println(userInput);
    System.out.println("echo: " + in.readLine());
}

```

`while`循环中的最后一个语句从连接到套接字的`BufferedReader`读取一行信息。 `readLine`方法等待，直到服务器将信息回送回`EchoClient`。当`readline`返回时，`EchoClient`将信息打印到标准输出。

`while`循环继续，直到用户键入输入结束字符。也就是说，`EchoClient`示例从用户读取输入，将其发送到 Echo 服务器，从服务器获取响应并显示它，直到它到达输入结束。 （您可以通过按 **Ctrl-C** 键入输入结束字符。）然后`while`循环终止，Java 运行时自动关闭连接到套接字和标准的读取器和写入器输入流，它关闭到服务器的套接字连接。 Java 运行时会自动关闭这些资源，因为它们是在`try` -with-resources 语句中创建的。 Java 运行时以与创建它们相反的顺序关闭这些资源。 （这很好，因为连接到套接字的流应该在套接字本身关闭之前关闭。）

此客户端程序简单明了，因为 echo 服务器实现了一个简单的协议。客户端将文本发送到服务器，服务器回送它。当您的客户端程序与更复杂的服务器（如 HTTP 服务器）通信时，您的客户端程序也会更复杂。但是，基础知识与此计划中的基本内容大致相同：

1.  打开一个插座。
2.  打开输入流并将输出流输出到套接字。
3.  根据服务器协议读取和写入流。
4.  关闭溪流。
5.  关闭插座。

只有步骤 3 因客户端而异，具体取决于服务器。其他步骤基本保持不变。