网络协议深入解析

2024/1/1

# 网络协议深入解析

# 1. 网络协议栈概述

# 1.1 OSI七层模型

应用层 (Application Layer)     - HTTP, HTTPS, FTP, SMTP, DNS
表示层 (Presentation Layer)    - 数据加密、压缩、格式转换
会话层 (Session Layer)         - 建立、管理、终止会话
传输层 (Transport Layer)       - TCP, UDP
网络层 (Network Layer)         - IP, ICMP, ARP
数据链路层 (Data Link Layer)   - 以太网, WiFi
物理层 (Physical Layer)        - 电缆, 光纤, 无线信号

# 1.2 TCP/IP四层模型

应用层 (Application Layer)     - HTTP, FTP, SMTP, DNS, SSH
传输层 (Transport Layer)       - TCP, UDP
网络层 (Internet Layer)        - IP, ICMP, ARP
网络接口层 (Network Interface)  - 以太网, WiFi

# 1.3 数据封装过程

应用数据 → [应用层协议头|数据] → [TCP/UDP头|应用数据] → [IP头|传输数据] → [以太网头|网络数据|以太网尾]

# 2. HTTP协议详解

# 2.1 HTTP协议特点

  • 无状态协议:每个请求都是独立的
  • 基于TCP:可靠的传输层协议
  • 请求-响应模式:客户端发起请求,服务器返回响应
  • 文本协议:使用可读的文本格式
  • 端口:默认使用80端口(HTTPS使用443端口)

# 2.2 HTTP请求格式

GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html,application/xhtml+xml
Connection: keep-alive

[请求体]

# 2.3 HTTP响应格式

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234
Server: Apache/2.4.41
Date: Mon, 01 Jan 2024 12:00:00 GMT

[响应体]

# 2.4 简单HTTP服务器实现

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;

public class SimpleHTTPServer {
    private static final int PORT = 8080;
    private static final String DOCUMENT_ROOT = "./www";
    private ExecutorService threadPool;
    private ServerSocket serverSocket;
    private volatile boolean running = false;
    
    public SimpleHTTPServer() {
        this.threadPool = Executors.newFixedThreadPool(10);
    }
    
    public void start() throws IOException {
        serverSocket = new ServerSocket(PORT);
        running = true;
        
        System.out.println("HTTP服务器启动,监听端口: " + PORT);
        System.out.println("文档根目录: " + DOCUMENT_ROOT);
        
        while (running) {
            try {
                Socket clientSocket = serverSocket.accept();
                threadPool.submit(new HTTPRequestHandler(clientSocket));
            } catch (IOException e) {
                if (running) {
                    System.err.println("接受连接异常: " + e.getMessage());
                }
            }
        }
    }
    
    public void stop() throws IOException {
        running = false;
        if (serverSocket != null && !serverSocket.isClosed()) {
            serverSocket.close();
        }
        threadPool.shutdown();
    }
    
    private static class HTTPRequestHandler implements Runnable {
        private final Socket clientSocket;
        
        public HTTPRequestHandler(Socket clientSocket) {
            this.clientSocket = clientSocket;
        }
        
        @Override
        public void run() {
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(clientSocket.getInputStream()));
                 OutputStream outputStream = clientSocket.getOutputStream()) {
                
                // 解析HTTP请求
                HTTPRequest request = parseRequest(reader);
                if (request != null) {
                    // 生成HTTP响应
                    HTTPResponse response = handleRequest(request);
                    // 发送响应
                    sendResponse(outputStream, response);
                }
                
            } catch (IOException e) {
                System.err.println("处理HTTP请求异常: " + e.getMessage());
            } finally {
                try {
                    clientSocket.close();
                } catch (IOException e) {
                    System.err.println("关闭连接异常: " + e.getMessage());
                }
            }
        }
        
        private HTTPRequest parseRequest(BufferedReader reader) throws IOException {
            String requestLine = reader.readLine();
            if (requestLine == null || requestLine.isEmpty()) {
                return null;
            }
            
            String[] parts = requestLine.split(" ");
            if (parts.length != 3) {
                return null;
            }
            
            String method = parts[0];
            String path = parts[1];
            String version = parts[2];
            
            Map<String, String> headers = new HashMap<>();
            String headerLine;
            while ((headerLine = reader.readLine()) != null && !headerLine.isEmpty()) {
                int colonIndex = headerLine.indexOf(':');
                if (colonIndex > 0) {
                    String headerName = headerLine.substring(0, colonIndex).trim();
                    String headerValue = headerLine.substring(colonIndex + 1).trim();
                    headers.put(headerName.toLowerCase(), headerValue);
                }
            }
            
            return new HTTPRequest(method, path, version, headers);
        }
        
        private HTTPResponse handleRequest(HTTPRequest request) {
            System.out.println("处理请求: " + request.getMethod() + " " + request.getPath());
            
            if (!"GET".equals(request.getMethod())) {
                return new HTTPResponse(405, "Method Not Allowed", 
                    "text/plain", "Method not allowed".getBytes());
            }
            
            String filePath = DOCUMENT_ROOT + request.getPath();
            if (request.getPath().equals("/")) {
                filePath += "/index.html";
            }
            
            File file = new File(filePath);
            if (!file.exists() || !file.isFile()) {
                return new HTTPResponse(404, "Not Found", 
                    "text/html", createErrorPage(404, "Not Found").getBytes());
            }
            
            try {
                byte[] content = readFile(file);
                String contentType = getContentType(file.getName());
                return new HTTPResponse(200, "OK", contentType, content);
            } catch (IOException e) {
                return new HTTPResponse(500, "Internal Server Error", 
                    "text/html", createErrorPage(500, "Internal Server Error").getBytes());
            }
        }
        
        private void sendResponse(OutputStream outputStream, HTTPResponse response) throws IOException {
            PrintWriter writer = new PrintWriter(outputStream, true);
            
            // 发送状态行
            writer.println("HTTP/1.1 " + response.getStatusCode() + " " + response.getReasonPhrase());
            
            // 发送响应头
            writer.println("Content-Type: " + response.getContentType());
            writer.println("Content-Length: " + response.getContent().length);
            writer.println("Server: SimpleHTTPServer/1.0");
            writer.println("Date: " + new Date());
            writer.println("Connection: close");
            writer.println(); // 空行分隔头部和正文
            
            // 发送响应体
            outputStream.write(response.getContent());
            outputStream.flush();
        }
        
        private byte[] readFile(File file) throws IOException {
            try (FileInputStream fis = new FileInputStream(file);
                 ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = fis.read(buffer)) != -1) {
                    baos.write(buffer, 0, bytesRead);
                }
                return baos.toByteArray();
            }
        }
        
        private String getContentType(String fileName) {
            if (fileName.endsWith(".html") || fileName.endsWith(".htm")) {
                return "text/html";
            } else if (fileName.endsWith(".css")) {
                return "text/css";
            } else if (fileName.endsWith(".js")) {
                return "application/javascript";
            } else if (fileName.endsWith(".json")) {
                return "application/json";
            } else if (fileName.endsWith(".png")) {
                return "image/png";
            } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
                return "image/jpeg";
            } else {
                return "application/octet-stream";
            }
        }
        
        private String createErrorPage(int statusCode, String message) {
            return "<html><head><title>" + statusCode + " " + message + 
                   "</title></head><body><h1>" + statusCode + " " + message + 
                   "</h1></body></html>";
        }
    }
    
    // HTTP请求类
    private static class HTTPRequest {
        private final String method;
        private final String path;
        private final String version;
        private final Map<String, String> headers;
        
        public HTTPRequest(String method, String path, String version, Map<String, String> headers) {
            this.method = method;
            this.path = path;
            this.version = version;
            this.headers = headers;
        }
        
        public String getMethod() { return method; }
        public String getPath() { return path; }
        public String getVersion() { return version; }
        public Map<String, String> getHeaders() { return headers; }
    }
    
    // HTTP响应类
    private static class HTTPResponse {
        private final int statusCode;
        private final String reasonPhrase;
        private final String contentType;
        private final byte[] content;
        
        public HTTPResponse(int statusCode, String reasonPhrase, String contentType, byte[] content) {
            this.statusCode = statusCode;
            this.reasonPhrase = reasonPhrase;
            this.contentType = contentType;
            this.content = content;
        }
        
        public int getStatusCode() { return statusCode; }
        public String getReasonPhrase() { return reasonPhrase; }
        public String getContentType() { return contentType; }
        public byte[] getContent() { return content; }
    }
    
    public static void main(String[] args) {
        SimpleHTTPServer server = new SimpleHTTPServer();
        
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                System.out.println("正在关闭HTTP服务器...");
                server.stop();
            } catch (IOException e) {
                System.err.println("关闭服务器异常: " + e.getMessage());
            }
        }));
        
        try {
            server.start();
        } catch (IOException e) {
            System.err.println("启动HTTP服务器失败: " + e.getMessage());
        }
    }
}

# 3. HTTPS协议详解

# 3.1 HTTPS vs HTTP

特性 HTTP HTTPS
安全性 明文传输 加密传输
端口 80 443
证书 不需要 需要SSL/TLS证书
性能 较快 较慢(加密开销)
SEO 一般 更好

# 3.2 SSL/TLS握手过程

客户端                           服务器
   |                               |
   |-------- Client Hello -------->|
   |<------- Server Hello --------|
   |<------- Certificate ---------|
   |<--- Server Hello Done -------|
   |                               |
   |--- Client Key Exchange ----->|
   |--- Change Cipher Spec ------>|
   |-------- Finished ----------->|
   |<-- Change Cipher Spec -------|
   |<------- Finished ------------|
   |                               |
   |     加密通信开始              |

# 3.3 简单HTTPS客户端实现

import javax.net.ssl.*;
import java.io.*;
import java.net.URL;
import java.security.cert.X509Certificate;

public class SimpleHTTPSClient {
    
    public static void main(String[] args) {
        // 测试HTTPS请求
        testHTTPSRequest("https://www.baidu.com");
        
        // 测试忽略证书验证的HTTPS请求
        testHTTPSWithoutCertValidation("https://self-signed.badssl.com/");
    }
    
    public static void testHTTPSRequest(String urlString) {
        try {
            URL url = new URL(urlString);
            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
            
            // 设置请求属性
            connection.setRequestMethod("GET");
            connection.setRequestProperty("User-Agent", "SimpleHTTPSClient/1.0");
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(10000);
            
            // 获取响应
            int responseCode = connection.getResponseCode();
            System.out.println("响应码: " + responseCode);
            System.out.println("响应消息: " + connection.getResponseMessage());
            
            // 显示证书信息
            displayCertificateInfo(connection);
            
            // 读取响应内容
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(connection.getInputStream()))) {
                String line;
                StringBuilder response = new StringBuilder();
                while ((line = reader.readLine()) != null) {
                    response.append(line).append("\n");
                }
                System.out.println("响应内容长度: " + response.length());
            }
            
        } catch (Exception e) {
            System.err.println("HTTPS请求异常: " + e.getMessage());
        }
    }
    
    public static void testHTTPSWithoutCertValidation(String urlString) {
        try {
            // 创建信任所有证书的TrustManager
            TrustManager[] trustAllCerts = new TrustManager[] {
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }
                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    }
                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    }
                }
            };
            
            // 创建SSLContext
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            
            // 创建不验证主机名的HostnameVerifier
            HostnameVerifier allHostsValid = (hostname, session) -> true;
            
            // 设置默认的SSLSocketFactory和HostnameVerifier
            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
            
            URL url = new URL(urlString);
            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
            
            int responseCode = connection.getResponseCode();
            System.out.println("忽略证书验证的响应码: " + responseCode);
            
        } catch (Exception e) {
            System.err.println("忽略证书验证的HTTPS请求异常: " + e.getMessage());
        }
    }
    
    private static void displayCertificateInfo(HttpsURLConnection connection) {
        try {
            System.out.println("\n=== 证书信息 ===");
            System.out.println("密码套件: " + connection.getCipherSuite());
            
            java.security.cert.Certificate[] certificates = connection.getServerCertificates();
            for (int i = 0; i < certificates.length; i++) {
                if (certificates[i] instanceof X509Certificate) {
                    X509Certificate cert = (X509Certificate) certificates[i];
                    System.out.println("证书 " + (i + 1) + ":");
                    System.out.println("  主题: " + cert.getSubjectDN());
                    System.out.println("  颁发者: " + cert.getIssuerDN());
                    System.out.println("  有效期: " + cert.getNotBefore() + " 到 " + cert.getNotAfter());
                    System.out.println("  序列号: " + cert.getSerialNumber());
                }
            }
            System.out.println("==================\n");
        } catch (Exception e) {
            System.err.println("获取证书信息异常: " + e.getMessage());
        }
    }
}

# 4. WebSocket协议详解

# 4.1 WebSocket特点

  • 全双工通信:客户端和服务器可以同时发送数据
  • 持久连接:连接建立后保持开放状态
  • 低延迟:无需HTTP请求/响应开销
  • 基于TCP:在TCP连接上建立WebSocket连接
  • 协议升级:从HTTP协议升级到WebSocket协议

# 4.2 WebSocket握手过程

# 客户端请求:

GET /websocket HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

# 服务器响应:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

# 4.3 简单WebSocket服务器实现

import java.io.*;
import java.net.*;
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SimpleWebSocketServer {
    private static final int PORT = 8081;
    private static final String WEBSOCKET_MAGIC_STRING = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    private static final List<WebSocketConnection> connections = new CopyOnWriteArrayList<>();
    
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
            System.out.println("WebSocket服务器启动,监听端口: " + PORT);
            
            while (true) {
                Socket clientSocket = serverSocket.accept();
                new Thread(() -> handleClient(clientSocket)).start();
            }
        } catch (IOException e) {
            System.err.println("WebSocket服务器异常: " + e.getMessage());
        }
    }
    
    private static void handleClient(Socket clientSocket) {
        try {
            // 执行WebSocket握手
            if (performHandshake(clientSocket)) {
                WebSocketConnection connection = new WebSocketConnection(clientSocket);
                connections.add(connection);
                System.out.println("新的WebSocket连接: " + clientSocket.getRemoteSocketAddress());
                
                // 处理WebSocket消息
                handleWebSocketMessages(connection);
            }
        } catch (Exception e) {
            System.err.println("处理WebSocket客户端异常: " + e.getMessage());
        } finally {
            try {
                clientSocket.close();
            } catch (IOException e) {
                System.err.println("关闭WebSocket连接异常: " + e.getMessage());
            }
        }
    }
    
    private static boolean performHandshake(Socket clientSocket) throws IOException {
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(clientSocket.getInputStream()));
        PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true);
        
        // 读取HTTP请求头
        String line;
        Map<String, String> headers = new HashMap<>();
        while ((line = reader.readLine()) != null && !line.isEmpty()) {
            if (line.contains(": ")) {
                String[] parts = line.split(": ", 2);
                headers.put(parts[0].toLowerCase(), parts[1]);
            }
        }
        
        // 验证WebSocket握手请求
        if (!"websocket".equalsIgnoreCase(headers.get("upgrade")) ||
            !"upgrade".equalsIgnoreCase(headers.get("connection")) ||
            !"13".equals(headers.get("sec-websocket-version"))) {
            return false;
        }
        
        // 生成Sec-WebSocket-Accept
        String webSocketKey = headers.get("sec-websocket-key");
        String acceptKey = generateAcceptKey(webSocketKey);
        
        // 发送握手响应
        writer.println("HTTP/1.1 101 Switching Protocols");
        writer.println("Upgrade: websocket");
        writer.println("Connection: Upgrade");
        writer.println("Sec-WebSocket-Accept: " + acceptKey);
        writer.println();
        
        return true;
    }
    
    private static String generateAcceptKey(String webSocketKey) {
        try {
            String combined = webSocketKey + WEBSOCKET_MAGIC_STRING;
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] hash = md.digest(combined.getBytes());
            return Base64.getEncoder().encodeToString(hash);
        } catch (Exception e) {
            throw new RuntimeException("生成WebSocket Accept Key失败", e);
        }
    }
    
    private static void handleWebSocketMessages(WebSocketConnection connection) {
        try {
            InputStream inputStream = connection.getSocket().getInputStream();
            
            while (true) {
                // 读取WebSocket帧
                WebSocketFrame frame = readFrame(inputStream);
                if (frame == null) {
                    break;
                }
                
                System.out.println("收到WebSocket消息: " + frame.getPayload());
                
                // 广播消息给所有连接的客户端
                broadcastMessage("Echo: " + frame.getPayload());
            }
        } catch (IOException e) {
            System.err.println("处理WebSocket消息异常: " + e.getMessage());
        } finally {
            connections.remove(connection);
        }
    }
    
    private static WebSocketFrame readFrame(InputStream inputStream) throws IOException {
        // 读取第一个字节(FIN + Opcode)
        int firstByte = inputStream.read();
        if (firstByte == -1) {
            return null;
        }
        
        boolean fin = (firstByte & 0x80) != 0;
        int opcode = firstByte & 0x0F;
        
        // 读取第二个字节(MASK + Payload Length)
        int secondByte = inputStream.read();
        if (secondByte == -1) {
            return null;
        }
        
        boolean masked = (secondByte & 0x80) != 0;
        int payloadLength = secondByte & 0x7F;
        
        // 处理扩展的payload length
        if (payloadLength == 126) {
            payloadLength = (inputStream.read() << 8) | inputStream.read();
        } else if (payloadLength == 127) {
            // 简化处理,实际应该读取8字节
            throw new IOException("不支持超长payload");
        }
        
        // 读取mask key
        byte[] maskKey = new byte[4];
        if (masked) {
            inputStream.read(maskKey);
        }
        
        // 读取payload
        byte[] payload = new byte[payloadLength];
        inputStream.read(payload);
        
        // 解码payload
        if (masked) {
            for (int i = 0; i < payload.length; i++) {
                payload[i] ^= maskKey[i % 4];
            }
        }
        
        return new WebSocketFrame(fin, opcode, new String(payload));
    }
    
    private static void broadcastMessage(String message) {
        byte[] messageBytes = message.getBytes();
        byte[] frame = createTextFrame(messageBytes);
        
        for (WebSocketConnection connection : connections) {
            try {
                connection.getSocket().getOutputStream().write(frame);
                connection.getSocket().getOutputStream().flush();
            } catch (IOException e) {
                System.err.println("发送消息失败: " + e.getMessage());
                connections.remove(connection);
            }
        }
    }
    
    private static byte[] createTextFrame(byte[] payload) {
        ByteArrayOutputStream frame = new ByteArrayOutputStream();
        
        // 第一个字节:FIN=1, Opcode=1 (text frame)
        frame.write(0x81);
        
        // 第二个字节:MASK=0, Payload Length
        if (payload.length < 126) {
            frame.write(payload.length);
        } else if (payload.length < 65536) {
            frame.write(126);
            frame.write((payload.length >> 8) & 0xFF);
            frame.write(payload.length & 0xFF);
        } else {
            throw new RuntimeException("Payload too large");
        }
        
        // Payload
        frame.writeBytes(payload);
        
        return frame.toByteArray();
    }
    
    private static class WebSocketConnection {
        private final Socket socket;
        
        public WebSocketConnection(Socket socket) {
            this.socket = socket;
        }
        
        public Socket getSocket() {
            return socket;
        }
    }
    
    private static class WebSocketFrame {
        private final boolean fin;
        private final int opcode;
        private final String payload;
        
        public WebSocketFrame(boolean fin, int opcode, String payload) {
            this.fin = fin;
            this.opcode = opcode;
            this.payload = payload;
        }
        
        public boolean isFin() { return fin; }
        public int getOpcode() { return opcode; }
        public String getPayload() { return payload; }
    }
}

# 5. FTP协议详解

# 5.1 FTP协议特点

  • 文件传输协议:专门用于文件传输
  • 双连接模式:控制连接(端口21)+ 数据连接
  • 主动/被动模式:支持两种数据传输模式
  • ASCII/二进制模式:支持不同的传输模式
  • 认证机制:支持用户名/密码认证

# 5.2 FTP工作模式

# 主动模式(Active Mode)

客户端 ----控制连接(21)----> 服务器
客户端 <---数据连接(20)---- 服务器

# 被动模式(Passive Mode)

客户端 ----控制连接(21)----> 服务器
客户端 ----数据连接(随机)---> 服务器

# 5.3 简单FTP客户端实现

import java.io.*;
import java.net.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SimpleFTPClient {
    private Socket controlSocket;
    private BufferedReader controlReader;
    private PrintWriter controlWriter;
    private String server;
    private int port;
    
    public SimpleFTPClient(String server, int port) {
        this.server = server;
        this.port = port;
    }
    
    public boolean connect() {
        try {
            controlSocket = new Socket(server, port);
            controlReader = new BufferedReader(
                new InputStreamReader(controlSocket.getInputStream()));
            controlWriter = new PrintWriter(
                controlSocket.getOutputStream(), true);
            
            // 读取欢迎消息
            String response = readResponse();
            System.out.println("服务器响应: " + response);
            
            return response.startsWith("220");
        } catch (IOException e) {
            System.err.println("连接FTP服务器失败: " + e.getMessage());
            return false;
        }
    }
    
    public boolean login(String username, String password) {
        try {
            // 发送用户名
            sendCommand("USER " + username);
            String response = readResponse();
            System.out.println("USER响应: " + response);
            
            if (!response.startsWith("331")) {
                return false;
            }
            
            // 发送密码
            sendCommand("PASS " + password);
            response = readResponse();
            System.out.println("PASS响应: " + response);
            
            return response.startsWith("230");
        } catch (IOException e) {
            System.err.println("FTP登录失败: " + e.getMessage());
            return false;
        }
    }
    
    public boolean enterPassiveMode() {
        try {
            sendCommand("PASV");
            String response = readResponse();
            System.out.println("PASV响应: " + response);
            
            if (!response.startsWith("227")) {
                return false;
            }
            
            // 解析被动模式响应,获取数据连接地址和端口
            Pattern pattern = Pattern.compile("\\((\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)\\)");
            Matcher matcher = pattern.matcher(response);
            
            if (matcher.find()) {
                String ip = matcher.group(1) + "." + matcher.group(2) + "." + 
                           matcher.group(3) + "." + matcher.group(4);
                int port = Integer.parseInt(matcher.group(5)) * 256 + 
                          Integer.parseInt(matcher.group(6));
                
                System.out.println("数据连接地址: " + ip + ":" + port);
                return true;
            }
            
            return false;
        } catch (IOException e) {
            System.err.println("进入被动模式失败: " + e.getMessage());
            return false;
        }
    }
    
    public void listFiles() {
        try {
            if (!enterPassiveMode()) {
                return;
            }
            
            sendCommand("LIST");
            String response = readResponse();
            System.out.println("LIST响应: " + response);
            
            // 实际实现中需要建立数据连接来接收文件列表
            
        } catch (IOException e) {
            System.err.println("列出文件失败: " + e.getMessage());
        }
    }
    
    public void changeDirectory(String directory) {
        try {
            sendCommand("CWD " + directory);
            String response = readResponse();
            System.out.println("CWD响应: " + response);
        } catch (IOException e) {
            System.err.println("切换目录失败: " + e.getMessage());
        }
    }
    
    public void printWorkingDirectory() {
        try {
            sendCommand("PWD");
            String response = readResponse();
            System.out.println("当前目录: " + response);
        } catch (IOException e) {
            System.err.println("获取当前目录失败: " + e.getMessage());
        }
    }
    
    public void disconnect() {
        try {
            if (controlSocket != null && !controlSocket.isClosed()) {
                sendCommand("QUIT");
                String response = readResponse();
                System.out.println("QUIT响应: " + response);
                
                controlSocket.close();
            }
        } catch (IOException e) {
            System.err.println("断开FTP连接失败: " + e.getMessage());
        }
    }
    
    private void sendCommand(String command) throws IOException {
        System.out.println("发送命令: " + command);
        controlWriter.println(command);
    }
    
    private String readResponse() throws IOException {
        StringBuilder response = new StringBuilder();
        String line;
        
        while ((line = controlReader.readLine()) != null) {
            response.append(line).append("\n");
            
            // FTP响应可能是多行的,检查是否结束
            if (line.length() >= 4 && line.charAt(3) == ' ') {
                break;
            }
        }
        
        return response.toString().trim();
    }
    
    public static void main(String[] args) {
        SimpleFTPClient client = new SimpleFTPClient("ftp.example.com", 21);
        
        if (client.connect()) {
            if (client.login("username", "password")) {
                client.printWorkingDirectory();
                client.listFiles();
                client.changeDirectory("/pub");
                client.printWorkingDirectory();
            }
            client.disconnect();
        }
    }
}

# 6. 网络协议分析工具

# 6.1 数据包捕获和分析

import java.io.*;
import java.net.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NetworkPacketAnalyzer {
    private static final int BUFFER_SIZE = 65536;
    private ExecutorService executor;
    
    public NetworkPacketAnalyzer() {
        this.executor = Executors.newCachedThreadPool();
    }
    
    public void startCapture(String networkInterface) {
        try {
            // 注意:Java标准库不直接支持原始套接字
            // 这里提供一个概念性的实现
            System.out.println("开始捕获网络数据包...");
            
            // 实际实现需要使用JNI或第三方库如jNetPcap
            simulatePacketCapture();
            
        } catch (Exception e) {
            System.err.println("数据包捕获异常: " + e.getMessage());
        }
    }
    
    private void simulatePacketCapture() {
        // 模拟数据包捕获
        for (int i = 0; i < 10; i++) {
            NetworkPacket packet = new NetworkPacket(
                "192.168.1.100", "192.168.1.1", 
                8080, 80, "HTTP", 
                "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".getBytes()
            );
            
            analyzePacket(packet);
            
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                break;
            }
        }
    }
    
    private void analyzePacket(NetworkPacket packet) {
        System.out.println("\n=== 数据包分析 ===");
        System.out.println("源地址: " + packet.getSourceIP() + ":" + packet.getSourcePort());
        System.out.println("目标地址: " + packet.getDestIP() + ":" + packet.getDestPort());
        System.out.println("协议: " + packet.getProtocol());
        System.out.println("数据长度: " + packet.getData().length + " 字节");
        
        // 协议特定分析
        if ("HTTP".equals(packet.getProtocol())) {
            analyzeHTTPPacket(packet);
        } else if ("TCP".equals(packet.getProtocol())) {
            analyzeTCPPacket(packet);
        }
        
        // 十六进制转储
        System.out.println("数据内容:");
        hexDump(packet.getData());
    }
    
    private void analyzeHTTPPacket(NetworkPacket packet) {
        String httpData = new String(packet.getData());
        String[] lines = httpData.split("\r\n");
        
        if (lines.length > 0) {
            System.out.println("HTTP请求行: " + lines[0]);
            
            for (int i = 1; i < lines.length && !lines[i].isEmpty(); i++) {
                System.out.println("HTTP头部: " + lines[i]);
            }
        }
    }
    
    private void analyzeTCPPacket(NetworkPacket packet) {
        // TCP包分析(简化版)
        byte[] data = packet.getData();
        if (data.length >= 20) {
            int sourcePort = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
            int destPort = ((data[2] & 0xFF) << 8) | (data[3] & 0xFF);
            long seqNum = ((long)(data[4] & 0xFF) << 24) | 
                         ((data[5] & 0xFF) << 16) | 
                         ((data[6] & 0xFF) << 8) | 
                         (data[7] & 0xFF);
            
            System.out.println("TCP源端口: " + sourcePort);
            System.out.println("TCP目标端口: " + destPort);
            System.out.println("TCP序列号: " + seqNum);
        }
    }
    
    private void hexDump(byte[] data) {
        int maxBytes = Math.min(data.length, 64); // 限制显示字节数
        
        for (int i = 0; i < maxBytes; i += 16) {
            System.out.printf("%04x: ", i);
            
            // 十六进制部分
            for (int j = 0; j < 16; j++) {
                if (i + j < maxBytes) {
                    System.out.printf("%02x ", data[i + j] & 0xFF);
                } else {
                    System.out.print("   ");
                }
            }
            
            System.out.print(" ");
            
            // ASCII部分
            for (int j = 0; j < 16 && i + j < maxBytes; j++) {
                byte b = data[i + j];
                if (b >= 32 && b <= 126) {
                    System.out.print((char) b);
                } else {
                    System.out.print(".");
                }
            }
            
            System.out.println();
        }
        
        if (data.length > maxBytes) {
            System.out.println("... (" + (data.length - maxBytes) + " 更多字节)");
        }
    }
    
    private static class NetworkPacket {
        private final String sourceIP;
        private final String destIP;
        private final int sourcePort;
        private final int destPort;
        private final String protocol;
        private final byte[] data;
        
        public NetworkPacket(String sourceIP, String destIP, int sourcePort, 
                           int destPort, String protocol, byte[] data) {
            this.sourceIP = sourceIP;
            this.destIP = destIP;
            this.sourcePort = sourcePort;
            this.destPort = destPort;
            this.protocol = protocol;
            this.data = data;
        }
        
        // Getters
        public String getSourceIP() { return sourceIP; }
        public String getDestIP() { return destIP; }
        public int getSourcePort() { return sourcePort; }
        public int getDestPort() { return destPort; }
        public String getProtocol() { return protocol; }
        public byte[] getData() { return data; }
    }
    
    public static void main(String[] args) {
        NetworkPacketAnalyzer analyzer = new NetworkPacketAnalyzer();
        analyzer.startCapture("eth0");
    }
}

# 7. 总结

本文深入解析了多种网络协议的特点和实现:

# 协议特点总结:

  1. HTTP协议

    • 无状态、基于TCP的应用层协议
    • 请求-响应模式,适用于Web应用
    • 简单易实现,但每次请求都需要建立连接
  2. HTTPS协议

    • 在HTTP基础上增加SSL/TLS加密
    • 提供数据加密、身份验证、数据完整性
    • 安全性高但性能开销较大
  3. WebSocket协议

    • 全双工通信,持久连接
    • 低延迟,适用于实时应用
    • 从HTTP协议升级而来
  4. FTP协议

    • 专门用于文件传输
    • 双连接模式(控制+数据)
    • 支持主动和被动模式

# 实现要点:

  1. 协议解析:正确解析协议头部和数据
  2. 状态管理:维护连接状态和会话信息
  3. 错误处理:处理网络异常和协议错误
  4. 性能优化:合理使用缓冲区和线程池
  5. 安全考虑:验证输入数据,防止攻击

# 选择建议:

  • Web应用:HTTP/HTTPS
  • 实时通信:WebSocket
  • 文件传输:FTP/SFTP
  • 简单数据交换:TCP/UDP Socket

理解这些协议的工作原理和实现细节,有助于开发更高效、更可靠的网络应用程序。