← 返回首页
🌐

Java网络编程详解:Socket与ServerSocket

📂 java ⏱ 4 min 604 words

Java网络编程详解:Socket与ServerSocket

概述

Java提供了丰富的网络编程API,支持TCP和UDP协议。本教程介绍Socket编程和NIO网络编程。

1. TCP Socket编程

服务器端

import java.io.*;
import java.net.*;

public class Server {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8080)) {
            System.out.println("服务器启动,等待连接...");
            
            while (true) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("客户端已连接: " + clientSocket.getInetAddress());
                
                // 处理客户端请求
                new Thread(() -> handleClient(clientSocket)).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private static void handleClient(Socket clientSocket) {
        try (BufferedReader in = new BufferedReader(
                new InputStreamReader(clientSocket.getInputStream()));
             PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) {
            
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                System.out.println("收到: " + inputLine);
                out.println("服务器收到: " + inputLine);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端

import java.io.*;
import java.net.*;

public class Client {
    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!");
            String response = in.readLine();
            System.out.println("服务器响应: " + response);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. UDP Socket编程

import java.net.*;
import java.util.*;

public class UDPServer {
    public static void main(String[] args) {
        try (DatagramSocket socket = new DatagramSocket(9090)) {
            System.out.println("UDP服务器启动...");
            
            byte[] buffer = new byte[1024];
            
            while (true) {
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                socket.receive(packet);
                
                String message = new String(packet.getData(), 0, packet.getLength());
                System.out.println("收到: " + message);
                
                // 发送响应
                InetAddress address = packet.getAddress();
                int port = packet.getPort();
                String response = "UDP响应: " + message;
                DatagramPacket responsePacket = new DatagramPacket(
                    response.getBytes(), response.length(), address, port);
                socket.send(responsePacket);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public class UDPClient {
    public static void main(String[] args) {
        try (DatagramSocket socket = new DatagramSocket()) {
            InetAddress address = InetAddress.getByName("localhost");
            
            String message = "Hello UDP Server!";
            DatagramPacket packet = new DatagramPacket(
                message.getBytes(), message.length(), address, 9090);
            socket.send(packet);
            
            // 接收响应
            byte[] buffer = new byte[1024];
            DatagramPacket responsePacket = new DatagramPacket(buffer, buffer.length);
            socket.receive(responsePacket);
            
            String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
            System.out.println("服务器响应: " + response);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3. NIO网络编程

import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.util.*;

public class NIOServer {
    public static void main(String[] args) {
        try {
            Selector selector = Selector.open();
            ServerSocketChannel serverChannel = ServerSocketChannel.open();
            serverChannel.configureBlocking(false);
            serverChannel.socket().bind(new java.net.InetSocketAddress(8080));
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);
            
            System.out.println("NIO服务器启动...");
            
            while (true) {
                selector.select();
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
                
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();
                    
                    if (key.isAcceptable()) {
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();
                        SocketChannel client = server.accept();
                        client.configureBlocking(false);
                        client.register(selector, SelectionKey.OP_READ);
                        System.out.println("新连接: " + client.getRemoteAddress());
                        
                    } else if (key.isReadable()) {
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        int bytesRead = client.read(buffer);
                        
                        if (bytesRead > 0) {
                            buffer.flip();
                            String message = StandardCharsets.UTF_8.decode(buffer).toString();
                            System.out.println("收到: " + message);
                            
                            // 发送响应
                            String response = "NIO响应: " + message;
                            ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());
                            client.write(responseBuffer);
                        }
                    }
                    
                    keyIterator.remove();
                }
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4. 实际应用示例

简单的聊天服务器

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

public class ChatServer {
    private static final Set<PrintWriter> clients = ConcurrentHashMap.newKeySet();
    
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8080)) {
            System.out.println("聊天服务器启动...");
            
            while (true) {
                Socket clientSocket = serverSocket.accept();
                new Thread(() -> handleClient(clientSocket)).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private static void handleClient(Socket clientSocket) {
        try (BufferedReader in = new BufferedReader(
                new InputStreamReader(clientSocket.getInputStream()));
             PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) {
            
            clients.add(out);
            
            String message;
            while ((message = in.readLine()) != null) {
                System.out.println("消息: " + message);
                broadcast(message);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 移除客户端
            clients.removeIf(out -> out.checkError());
        }
    }
    
    private static void broadcast(String message) {
        for (PrintWriter client : clients) {
            client.println(message);
        }
    }
}

5. 最佳实践

  1. 使用try-with-resources:自动关闭资源
  2. 使用NIO:高并发场景使用NIO
  3. 处理异常:妥善处理IOException
  4. 使用线程池:管理客户端连接
  5. 设置超时:避免长时间阻塞

总结

Java网络编程提供了丰富的API。掌握Socket编程和NIO网络编程,可以实现各种网络应用。在实际编程中,要根据需求选择合适的网络编程方式。