一、Socket编程基础
Socket是网络通信的基石,提供了端到端的通信机制。想象它就像电话系统,两端通过Socket建立连接后就可以互相通信。
TCP Socket编程
// 服务器端
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编程
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
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详解
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模型
// 传统阻塞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模型
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服务器
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();}}
}
最佳实践建议 💡
- 连接管理
- 使用连接池管理连接
- 设置合适的超时时间
- 正确关闭资源
- 错误处理
- 实现重试机制
- 记录详细的错误日志
- 性能优化
- 使用非阻塞IO处理高并发
- 实现数据压缩
- 使用缓冲区提高效率
常见陷阱提醒 ⚠️
- 资源泄露
// 错误:未关闭资源
Socket socket = new Socket("localhost", 8080);
socket.getOutputStream().write(data);
// 应该使用try-with-resources// 正确做法
try (Socket socket = new Socket("localhost", 8080)) {socket.getOutputStream().write(data);
}
- 超时处理
// 错误:未设置超时
URLConnection conn = url.openConnection();
InputStream in = conn.getInputStream(); // 可能永远阻塞// 正确做法
URLConnection conn = url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
- 并发处理
// 错误:每个连接创建新线程
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));
}
网络编程是现代应用程序的重要组成部分。掌握这些基础知识对于构建可靠的网络应用至关重要。记住要注意资源管理、错误处理和性能优化。