【Java入门指南 Day15:Java网络编程】

一、Socket编程基础

Socket是网络通信的基石,提供了端到端的通信机制。想象它就像电话系统,两端通过Socket建立连接后就可以互相通信。

TCP Socket编程

java 复制代码
// 服务器端
public class SimpleServer {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8080)) {
            System.out.println("服务器启动,等待连接...");
            
            while (true) {
                Socket clientSocket = serverSocket.accept();
                handleClient(clientSocket);
            }
        }
    }
    
    private static void handleClient(Socket socket) {
        try (BufferedReader in = new BufferedReader(
                new InputStreamReader(socket.getInputStream()));
             PrintWriter out = new PrintWriter(
                socket.getOutputStream(), true)) {
            
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println("收到消息: " + line);
                out.println("服务器已收到: " + line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// 客户端
public class SimpleClient {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 8080);
             PrintWriter out = new PrintWriter(
                socket.getOutputStream(), true);
             BufferedReader in = new BufferedReader(
                new InputStreamReader(socket.getInputStream()))) {
            
            out.println("Hello, Server!");
            System.out.println("服务器响应: " + in.readLine());
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

UDP Socket编程

java 复制代码
public class UDPExample {
    public static void main(String[] args) throws IOException {
        // UDP服务器
        DatagramSocket serverSocket = new DatagramSocket(9000);
        byte[] receiveData = new byte[1024];
        
        while (true) {
            DatagramPacket receivePacket = 
                new DatagramPacket(receiveData, receiveData.length);
            serverSocket.receive(receivePacket);
            
            String message = new String(
                receivePacket.getData(), 0, receivePacket.getLength());
            System.out.println("收到消息: " + message);
        }
    }
}

二、HTTP客户端实现

使用HttpURLConnection

java 复制代码
public class HttpClientExample {
    public String sendGet(String url) throws IOException {
        HttpURLConnection connection = (HttpURLConnection) 
            new URL(url).openConnection();
        connection.setRequestMethod("GET");
        connection.setConnectTimeout(5000);
        connection.setReadTimeout(5000);
        
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(connection.getInputStream()))) {
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            return response.toString();
        } finally {
            connection.disconnect();
        }
    }
    
    public String sendPost(String url, String body) throws IOException {
        HttpURLConnection connection = (HttpURLConnection) 
            new URL(url).openConnection();
        connection.setRequestMethod("POST");
        connection.setDoOutput(true);
        connection.setRequestProperty("Content-Type", "application/json");
        
        try (OutputStream os = connection.getOutputStream()) {
            os.write(body.getBytes());
        }
        
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(connection.getInputStream()))) {
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            return response.toString();
        }
    }
}

三、URL和URLConnection详解

java 复制代码
public class URLExample {
    public static void main(String[] args) throws Exception {
        URL url = new URL("https://api.example.com/data?id=123");
        
        System.out.println("协议: " + url.getProtocol());
        System.out.println("主机: " + url.getHost());
        System.out.println("端口: " + url.getPort());
        System.out.println("路径: " + url.getPath());
        System.out.println("查询参数: " + url.getQuery());
        
        URLConnection connection = url.openConnection();
        connection.setConnectTimeout(5000);
        connection.setReadTimeout(5000);
        
        // 设置请求属性
        connection.setRequestProperty("User-Agent", "Mozilla/5.0");
        
        // 获取响应头
        for (Map.Entry<String, List<String>> header : 
             connection.getHeaderFields().entrySet()) {
            System.out.println(header.getKey() + ": " + header.getValue());
        }
    }
}

四、网络IO模型

1. 阻塞IO模型

java 复制代码
// 传统阻塞IO
ServerSocket serverSocket = new ServerSocket(8080);
Socket socket = serverSocket.accept(); // 阻塞直到连接建立
InputStream in = socket.getInputStream();
byte[] buffer = new byte[1024];
int read = in.read(buffer); // 阻塞直到有数据可读

2. 非阻塞IO模型

java 复制代码
public class NonBlockingServer {
    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.bind(new InetSocketAddress(8080));
        serverChannel.configureBlocking(false);
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        
        while (true) {
            selector.select();
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> iter = selectedKeys.iterator();
            
            while (iter.hasNext()) {
                SelectionKey key = iter.next();
                if (key.isAcceptable()) {
                    handleAccept(serverChannel, selector);
                } else if (key.isReadable()) {
                    handleRead(key);
                }
                iter.remove();
            }
        }
    }
}

五、实用案例:简单的HTTP服务器

java 复制代码
public class SimpleHttpServer {
    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(8080);
        System.out.println("HTTP服务器启动,监听端口8080...");
        
        while (true) {
            Socket clientSocket = server.accept();
            new Thread(() -> handleRequest(clientSocket)).start();
        }
    }
    
    private static void handleRequest(Socket socket) {
        try (BufferedReader in = new BufferedReader(
                new InputStreamReader(socket.getInputStream()));
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
            
            // 读取HTTP请求
            String requestLine = in.readLine();
            System.out.println("收到请求: " + requestLine);
            
            // 发送HTTP响应
            out.println("HTTP/1.1 200 OK");
            out.println("Content-Type: text/html; charset=utf-8");
            out.println();
            out.println("<html><body><h1>Hello, World!</h1></body></html>");
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

最佳实践建议 💡

  1. 连接管理
    • 使用连接池管理连接
    • 设置合适的超时时间
    • 正确关闭资源
  2. 错误处理
    • 实现重试机制
    • 记录详细的错误日志
  3. 性能优化
    • 使用非阻塞IO处理高并发
    • 实现数据压缩
    • 使用缓冲区提高效率

常见陷阱提醒 ⚠️

  1. 资源泄露
java 复制代码
// 错误:未关闭资源
Socket socket = new Socket("localhost", 8080);
socket.getOutputStream().write(data);
// 应该使用try-with-resources

// 正确做法
try (Socket socket = new Socket("localhost", 8080)) {
    socket.getOutputStream().write(data);
}
  1. 超时处理
java 复制代码
// 错误:未设置超时
URLConnection conn = url.openConnection();
InputStream in = conn.getInputStream(); // 可能永远阻塞

// 正确做法
URLConnection conn = url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
  1. 并发处理
java 复制代码
// 错误:每个连接创建新线程
while (true) {
    Socket socket = serverSocket.accept();
    new Thread(() -> handleRequest(socket)).start();
}

// 正确:使用线程池
ExecutorService executor = Executors.newFixedThreadPool(10);
while (true) {
    Socket socket = serverSocket.accept();
    executor.submit(() -> handleRequest(socket));
}

网络编程是现代应用程序的重要组成部分。掌握这些基础知识对于构建可靠的网络应用至关重要。记住要注意资源管理、错误处理和性能优化。

相关推荐
小_太_阳22 分钟前
Scala_【2】变量和数据类型
开发语言·后端·scala·intellij-idea
直裾25 分钟前
scala借阅图书保存记录(三)
开发语言·后端·scala
黑胡子大叔的小屋42 分钟前
基于springboot的海洋知识服务平台的设计与实现
java·spring boot·毕业设计
ThisIsClark1 小时前
【后端面试总结】深入解析进程和线程的区别
java·jvm·面试
唐 城1 小时前
curl 放弃对 Hyper Rust HTTP 后端的支持
开发语言·http·rust
雷神乐乐2 小时前
Spring学习(一)——Sping-XML
java·学习·spring
小林coding2 小时前
阿里云 Java 后端一面,什么难度?
java·后端·mysql·spring·阿里云
V+zmm101342 小时前
基于小程序宿舍报修系统的设计与实现ssm+论文源码调试讲解
java·小程序·毕业设计·mvc·ssm
码银3 小时前
【python】银行客户流失预测预处理部分,独热编码·标签编码·数据离散化处理·数据筛选·数据分割
开发语言·python
从善若水3 小时前
【2024】Merry Christmas!一起用Rust绘制一颗圣诞树吧
开发语言·后端·rust