通过前两个小节的讲解,了解了 ServerSocket、Socket 类的基本用法。为了更好的掌握这两个类的使用,接下来通过一个 TCP 通信的案例来进一步学习这两个类的用法。

    要实现 TCP 通信需要创建一个服务器端程序和客户端程序,为了保证数据传输的安全性,首先需要实现服务器端程序,如下所示:

    1. import java.io.OutputStream;
    2. import java.net.*;
    3. public class Server {
    4. public static void main(String[] args) throws Exception {
    5. //创建 TCPServer 对象,并调用 listen()方法
    6. new TCPServer().listen();
    7. }
    8. }
    9. //TCPServer 服务端
    10. class TCPServer{
    11. private static final int PORT = 7788; //定义一个端口
    12. //定义一个 listen()方法,抛出异常
    13. public void listen() throws Exception {
    14. //创建 ServerSocket 对象
    15. ServerSocket serverSocket = new ServerSocket(PORT);
    16. //调用 ServerSocket 的 accept()方法接收数据
    17. Socket client = serverSocket.accept();
    18. //获取客户端的输出流
    19. OutputStream os = client.getOutputStream();
    20. System.out.println("开始与客户端交互数据");
    21. //当客户端连接到服务端时,向客户端输出数据
    22. os.write(("我爱你").getBytes());
    23. Thread.sleep(5000); //模拟执行其他功能占用的时间
    24. System.out.println("结束与客户端交互数据");
    25. os.close();
    26. client.close();
    27. }
    28. }

    运行结果如下所示:
    image.png
    上述代码块中创建了一个服务器端程序,用于接收客户端发送的数据。在创建 ServerSocket 对象时指定了端口号,并调用该对象的 accept()方法。从运行结果可以看出,控制台中的光标一直在闪动,这是因为 accept()方法发生阻塞,程序暂时停止运行,直到有客户端来访问时才会结束这种阻塞状态。这时该方法会返回一个 Socket 类型的对象用于表示客户端,通过该对象获取与客户端关联的输出流,并向客户端发送消息,同时执行 Thread.sleep(5000)语句模拟服务器执行其他功能占用的时间。最后,调用 Socket 对象的 close()方法将通信关闭。

    接下来编写客户端程序,如下所示:

    import java.io.InputStream;
    import java.net.*;
    
    public class Client {
        public static void main(String[] args) throws Exception {
            //创建 TCPClient 对象,调用 connect()方法
            new TCPClient().connect();
        }
    }
    //TCP 客户端
    class TCPClient{
        private static final int PORT = 7788;    //定义一个端口
        public void connect() throws Exception, Exception {
            //创建一个 Socket 并连接到给出地址和端口号的计算机
            Socket client = new Socket(InetAddress.getLocalHost(), PORT);
            InputStream is = client.getInputStream();    //得到数据的流
            //定义一个 1024 个字节数数组的缓冲区
            byte[] buf = new byte[1024];
            int len = is.read(buf);    //将数据读到缓冲区中
            System.out.println(new String(buf, 0, len));    //将缓冲区中的数据输出
            is.close();
            client.close();
        }
    }
    

    运行结果如下所示:
    image.png
    上述代码块中,创建了一个客户端程序,用于向服务端发送数据。在客户端创建的 Socket 对象与服务器端建立连接后,通过 Socket 对象获得输入流读取服务端发来的数据,并打印出下图所示的结果。同时,服务端程序会结束阻塞状态,并在控制台打印出“开始与客户端交互数据”消息,然后向客户端发出数据“我爱你”,在休眠 5 秒后,打印出“结束与客户端交互数据”,此时本次通信结束。如下图所示。
    image.png