Java TCP 通信:实现简单的 Echo 服务器与客户端

TCP(Transmission Control Protocol)是一种面向连接的、可靠的传输层协议。与 UDP 不同,TCP 保证了数据的顺序、可靠性和完整性,适用于需要可靠传输的应用场景,如文件传输、网页浏览等。本文将基于 Java 实现一个简单的 TCP Echo 服务器和客户端,并通过代码总结相关的知识点。


1. TCP Echo 服务器

1.1 服务器代码结构

java 复制代码
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpEchoServer {
    private ServerSocket serverSocket = null;

    public TcpEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");
        ExecutorService executorService = Executors.newCachedThreadPool();
        while (true) {
            // 通过 accept 方法,把内核中已经建立好的连接拿到应用程序中
            Socket clientSocket = serverSocket.accept();
            // 使用线程池处理客户端连接
            executorService.submit(() -> {
                try {
                    processConnection(clientSocket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }

    // 通过这个方法,来处理连接
    public void processConnection(Socket clientSocket) throws IOException {
        // 打印客户端上线日志
        System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress(), clientSocket.getPort());
        try (InputStream inputStream = clientSocket.getInputStream();
             OutputStream outputStream = clientSocket.getOutputStream()) {
            // 使用 Scanner 读取客户端请求
            Scanner scanner = new Scanner(inputStream);
            while (true) {
                if (!scanner.hasNext()) {
                    // 连接断开
                    System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());
                    break;
                }
                // 1. 读取请求并解析
                String request = scanner.next();
                // 2. 根据请求计算响应
                String response = process(request);
                // 3. 把响应写回到客户端
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(response);
                printWriter.flush();
                // 4. 打印请求交互的内容
                System.out.printf("[%s:%d] req=%s, resp=%s\n", clientSocket.getInetAddress(), clientSocket.getPort(),
                        request, response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            clientSocket.close();
        }
    }

    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer server = new TcpEchoServer(9090);
        server.start();
    }
}
1.2 服务器代码解析
ServerSocket:ServerSocket 是 Java 中用于监听客户端连接的类。服务器通过 ServerSocket 绑定到指定端口,等待客户端连接。

Socket:Socket 是 Java 中用于表示客户端连接的类。服务器通过 serverSocket.accept() 方法获取客户端的连接,并返回一个 Socket 对象。

线程池:为了支持多客户端并发连接,服务器使用 ExecutorService 线程池来处理每个客户端的请求。Executors.newCachedThreadPool() 创建了一个可缓存的线程池,根据需要创建新线程。

processConnection():该方法用于处理客户端连接。它通过 InputStream 和 OutputStream 与客户端进行数据交互。

Scanner:Scanner 用于从 InputStream 中读取客户端发送的请求数据。

PrintWriter:PrintWriter 用于将响应数据写入 OutputStream,并发送给客户端。

日志打印:服务器在处理每个请求后,会打印客户端的地址、端口、请求内容和响应内容,方便调试和监控。

2. TCP Echo 客户端
2.1 客户端代码结构
java

复制

import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoClient {
    private Socket socket = null;

    public TcpEchoClient(String serverIP, int serverPort) throws IOException {
        socket = new Socket(serverIP, serverPort);
    }

    public void start() {
        Scanner scanner = new Scanner(System.in);
        try (InputStream inputStream = socket.getInputStream();
             OutputStream outputStream = socket.getOutputStream()) {
            PrintWriter writer = new PrintWriter(outputStream);
            Scanner scannerNetwork = new Scanner(inputStream);
            while (true) {
                // 从控制台读取用户输入
                System.out.print("-> ");
                String request = scanner.next();
                // 发送请求到服务器
                writer.println(request);
                writer.flush();
                // 读取服务器响应
                String response = scannerNetwork.next();
                System.out.println(response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);
        client.start();
    }
}

2. TCP Echo 客户端

2.1 客户端代码结构

java 复制代码
import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoClient {
    private Socket socket = null;

    public TcpEchoClient(String serverIP, int serverPort) throws IOException {
        socket = new Socket(serverIP, serverPort);
    }

    public void start() {
        Scanner scanner = new Scanner(System.in);
        try (InputStream inputStream = socket.getInputStream();
             OutputStream outputStream = socket.getOutputStream()) {
            PrintWriter writer = new PrintWriter(outputStream);
            Scanner scannerNetwork = new Scanner(inputStream);
            while (true) {
                // 从控制台读取用户输入
                System.out.print("-> ");
                String request = scanner.next();
                // 发送请求到服务器
                writer.println(request);
                writer.flush();
                // 读取服务器响应
                String response = scannerNetwork.next();
                System.out.println(response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);
        client.start();
    }
}

2.2 客户端代码解析

  1. Socket :客户端通过 Socket 连接到服务器。Socket 的构造函数需要指定服务器的 IP 地址和端口号。

  2. InputStreamOutputStream :客户端通过 InputStream 读取服务器返回的响应数据,通过 OutputStream 发送请求数据。

  3. PrintWriterPrintWriter 用于将请求数据写入 OutputStream,并发送给服务器。

  4. ScannerScanner 用于从控制台读取用户输入,并从 InputStream 中读取服务器返回的响应数据。

  5. 循环交互:客户端通过一个无限循环,不断从控制台读取用户输入,发送请求并接收响应。


3. 总结

通过实现这个简单的 TCP Echo 服务器和客户端,我们可以总结出以下知识点:

  1. TCP 协议的特点:TCP 是一种面向连接的协议,保证了数据的顺序、可靠性和完整性,适用于需要可靠传输的应用场景。

  2. ServerSocketSocket :这两个类是 Java 中实现 TCP 通信的核心类。ServerSocket 用于监听客户端连接,Socket 用于表示客户端连接。

  3. 多线程处理:为了支持多客户端并发连接,服务器使用线程池来处理每个客户端的请求。

  4. 流操作InputStreamOutputStream 是 Java 中用于读写数据的核心类。通过 ScannerPrintWriter,可以方便地进行文本数据的读写。

  5. 日志与调试:在实际开发中,打印日志是非常重要的,它可以帮助我们监控程序的运行状态,排查问题。

  6. Echo 服务器的应用:Echo 服务器是一种简单的网络服务,它将客户端发送的数据原样返回。虽然简单,但它可以帮助我们理解网络通信的基本原理。

相关推荐
乂爻yiyao2 小时前
Java LTS版本重要升级特性对照表
java·开发语言
原来是好奇心2 小时前
深入Spring Boot源码(六):Actuator端点与监控机制深度解析
java·开发语言·源码·springboot
小卒过河01042 小时前
使用apache nifi 从数据库文件表路径拉取远程文件至远程服务器目的地址
运维·服务器·数据库
叠叠乐2 小时前
robot_state_publisher 参数
java·前端·算法
过期动态2 小时前
JDBC高级篇:优化、封装与事务全流程指南
android·java·开发语言·数据库·python·mysql
WizLC2 小时前
【Java】各种IO流知识详解
java·开发语言·后端·spring·intellij idea
Mr.朱鹏2 小时前
SQL深度分页问题案例实战
java·数据库·spring boot·sql·spring·spring cloud·kafka
土星云SaturnCloud2 小时前
液冷“内卷”:在局部优化与系统重构之间,寻找第三条路
服务器·人工智能·ai·计算机外设
小张快跑。2 小时前
【Java企业级开发】(十一)企业级Web应用程序Servlet框架的使用(上)
java·前端·servlet