网络编程基础 #
一、网络通信概述 #
1.1 网络协议栈 #
text
┌─────────────────────────────────────────────────────────┐
│ TCP/IP协议栈 │
├─────────────────────────────────────────────────────────┤
│ │
│ 应用层:HTTP, MQTT, CoAP, WebSocket │
│ ───────────────────────────────────────────── │
│ 传输层:TCP (可靠), UDP (快速) │
│ ───────────────────────────────────────────── │
│ 网络层:IP (寻址, 路由) │
│ ───────────────────────────────────────────── │
│ 链路层:Ethernet, WiFi │
│ │
└─────────────────────────────────────────────────────────┘
1.2 TCP vs UDP #
| 特性 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接 | 无连接 |
| 可靠性 | 可靠传输 | 尽力传输 |
| 顺序 | 有序 | 无序 |
| 速度 | 较慢 | 较快 |
| 应用 | 文件传输、控制 | 视频流、传感器数据 |
1.3 端口号 #
| 端口范围 | 用途 |
|---|---|
| 0-1023 | 知名端口(系统保留) |
| 1024-49151 | 注册端口 |
| 49152-65535 | 动态/私有端口 |
二、TCP Socket编程 #
2.1 TCP服务器 #
java
package com.example.network;
import java.io.*;
import java.net.*;
import java.util.concurrent.*;
import java.util.function.Consumer;
public class TCPServer {
private final int port;
private ServerSocket serverSocket;
private volatile boolean running = false;
private final ExecutorService executor = Executors.newCachedThreadPool();
private final Map<String, ClientHandler> clients = new ConcurrentHashMap<>();
private Consumer<String> messageHandler;
private Consumer<String> connectHandler;
private Consumer<String> disconnectHandler;
public TCPServer(int port) {
this.port = port;
}
public void start() throws IOException {
serverSocket = new ServerSocket(port);
running = true;
System.out.println("TCP服务器启动,端口: " + port);
executor.submit(() -> {
while (running) {
try {
Socket clientSocket = serverSocket.accept();
ClientHandler handler = new ClientHandler(clientSocket);
clients.put(handler.getId(), handler);
executor.submit(handler);
if (connectHandler != null) {
connectHandler.accept(handler.getId());
}
} catch (IOException e) {
if (running) {
e.printStackTrace();
}
}
}
});
}
public void stop() {
running = false;
for (ClientHandler handler : clients.values()) {
handler.close();
}
clients.clear();
try {
if (serverSocket != null) {
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
executor.shutdown();
}
public void send(String clientId, String message) {
ClientHandler handler = clients.get(clientId);
if (handler != null) {
handler.send(message);
}
}
public void broadcast(String message) {
for (ClientHandler handler : clients.values()) {
handler.send(message);
}
}
public void onMessage(Consumer<String> handler) {
this.messageHandler = handler;
}
public void onConnect(Consumer<String> handler) {
this.connectHandler = handler;
}
public void onDisconnect(Consumer<String> handler) {
this.disconnectHandler = handler;
}
private class ClientHandler implements Runnable {
private final Socket socket;
private final String id;
private BufferedReader reader;
private PrintWriter writer;
public ClientHandler(Socket socket) {
this.socket = socket;
this.id = socket.getRemoteSocketAddress().toString();
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer = new PrintWriter(socket.getOutputStream(), true);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
String line;
while ((line = reader.readLine()) != null) {
if (messageHandler != null) {
messageHandler.accept(id + ":" + line);
}
}
} catch (IOException e) {
// 客户端断开连接
} finally {
close();
clients.remove(id);
if (disconnectHandler != null) {
disconnectHandler.accept(id);
}
}
}
public void send(String message) {
if (writer != null) {
writer.println(message);
}
}
public void close() {
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public String getId() {
return id;
}
}
public static void main(String[] args) throws IOException {
TCPServer server = new TCPServer(8080);
server.onConnect(id -> System.out.println("客户端连接: " + id));
server.onDisconnect(id -> System.out.println("客户端断开: " + id));
server.onMessage(msg -> {
System.out.println("收到消息: " + msg);
server.broadcast("Echo: " + msg);
});
server.start();
Runtime.getRuntime().addShutdownHook(new Thread(server::stop));
}
}
2.2 TCP客户端 #
java
package com.example.network;
import java.io.*;
import java.net.*;
import java.util.function.Consumer;
public class TCPClient {
private final String host;
private final int port;
private Socket socket;
private BufferedReader reader;
private PrintWriter writer;
private volatile boolean connected = false;
private Consumer<String> messageHandler;
public TCPClient(String host, int port) {
this.host = host;
this.port = port;
}
public void connect() throws IOException {
socket = new Socket(host, port);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer = new PrintWriter(socket.getOutputStream(), true);
connected = true;
new Thread(() -> {
try {
String line;
while (connected && (line = reader.readLine()) != null) {
if (messageHandler != null) {
messageHandler.accept(line);
}
}
} catch (IOException e) {
if (connected) {
e.printStackTrace();
}
} finally {
connected = false;
}
}).start();
System.out.println("已连接到 " + host + ":" + port);
}
public void disconnect() {
connected = false;
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void send(String message) {
if (writer != null && connected) {
writer.println(message);
}
}
public void onMessage(Consumer<String> handler) {
this.messageHandler = handler;
}
public boolean isConnected() {
return connected;
}
public static void main(String[] args) throws IOException, InterruptedException {
TCPClient client = new TCPClient("localhost", 8080);
client.onMessage(msg -> System.out.println("收到: " + msg));
client.connect();
for (int i = 0; i < 10; i++) {
client.send("Hello " + i);
Thread.sleep(1000);
}
client.disconnect();
}
}
三、UDP编程 #
3.1 UDP服务器 #
java
package com.example.network;
import java.net.*;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
public class UDPServer {
private final int port;
private DatagramSocket socket;
private volatile boolean running = false;
private final ExecutorService executor = Executors.newSingleThreadExecutor();
private BiConsumer<SocketAddress, byte[]> messageHandler;
public UDPServer(int port) {
this.port = port;
}
public void start() throws SocketException {
socket = new DatagramSocket(port);
running = true;
System.out.println("UDP服务器启动,端口: " + port);
executor.submit(() -> {
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (running) {
try {
socket.receive(packet);
byte[] data = new byte[packet.getLength()];
System.arraycopy(packet.getData(), 0, data, 0, packet.getLength());
if (messageHandler != null) {
messageHandler.accept(packet.getSocketAddress(), data);
}
} catch (IOException e) {
if (running) {
e.printStackTrace();
}
}
}
});
}
public void stop() {
running = false;
if (socket != null) {
socket.close();
}
executor.shutdown();
}
public void send(SocketAddress address, byte[] data) throws IOException {
DatagramPacket packet = new DatagramPacket(data, data.length, address);
socket.send(packet);
}
public void send(SocketAddress address, String message) throws IOException {
send(address, message.getBytes());
}
public void onMessage(BiConsumer<SocketAddress, byte[]> handler) {
this.messageHandler = handler;
}
public static void main(String[] args) throws SocketException, InterruptedException {
UDPServer server = new UDPServer(9090);
server.onMessage((address, data) -> {
String message = new String(data);
System.out.println("收到来自 " + address + ": " + message);
try {
server.send(address, "Echo: " + message);
} catch (IOException e) {
e.printStackTrace();
}
});
server.start();
Thread.sleep(60000);
server.stop();
}
}
3.2 UDP客户端 #
java
package com.example.network;
import java.net.*;
import java.util.function.Consumer;
public class UDPClient {
private final String host;
private final int port;
private DatagramSocket socket;
private InetSocketAddress serverAddress;
private volatile boolean running = false;
private Consumer<byte[]> responseHandler;
public UDPClient(String host, int port) {
this.host = host;
this.port = port;
}
public void connect() throws SocketException {
socket = new DatagramSocket();
serverAddress = new InetSocketAddress(host, port);
running = true;
new Thread(() -> {
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (running) {
try {
socket.receive(packet);
byte[] data = new byte[packet.getLength()];
System.arraycopy(packet.getData(), 0, data, 0, packet.getLength());
if (responseHandler != null) {
responseHandler.accept(data);
}
} catch (IOException e) {
if (running) {
e.printStackTrace();
}
}
}
}).start();
}
public void disconnect() {
running = false;
if (socket != null) {
socket.close();
}
}
public void send(byte[] data) throws IOException {
DatagramPacket packet = new DatagramPacket(data, data.length, serverAddress);
socket.send(packet);
}
public void send(String message) throws IOException {
send(message.getBytes());
}
public void onResponse(Consumer<byte[]> handler) {
this.responseHandler = handler;
}
public static void main(String[] args) throws IOException, InterruptedException {
UDPClient client = new UDPClient("localhost", 9090);
client.onResponse(data -> System.out.println("收到响应: " + new String(data)));
client.connect();
for (int i = 0; i < 10; i++) {
client.send("Hello UDP " + i);
Thread.sleep(1000);
}
client.disconnect();
}
}
四、网络工具类 #
4.1 网络信息获取 #
java
package com.example.network;
import java.net.*;
import java.util.*;
public class NetworkUtils {
public static String getLocalIPAddress() throws SocketException {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface iface = interfaces.nextElement();
if (iface.isLoopback() || !iface.isUp()) {
continue;
}
Enumeration<InetAddress> addresses = iface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress addr = addresses.nextElement();
if (addr instanceof Inet4Address && !addr.isLoopbackAddress()) {
return addr.getHostAddress();
}
}
}
return null;
}
public static List<String> getAllIPAddresses() throws SocketException {
List<String> ips = new ArrayList<>();
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface iface = interfaces.nextElement();
if (iface.isLoopback() || !iface.isUp()) {
continue;
}
Enumeration<InetAddress> addresses = iface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress addr = addresses.nextElement();
if (!addr.isLoopbackAddress()) {
ips.add(addr.getHostAddress());
}
}
}
return ips;
}
public static String getMACAddress() throws SocketException {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface iface = interfaces.nextElement();
if (iface.isLoopback() || !iface.isUp()) {
continue;
}
byte[] mac = iface.getHardwareAddress();
if (mac != null) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mac.length; i++) {
sb.append(String.format("%02X", mac[i]));
if (i < mac.length - 1) {
sb.append(":");
}
}
return sb.toString();
}
}
return null;
}
public static boolean isPortAvailable(int port) {
try (ServerSocket socket = new ServerSocket(port)) {
socket.setReuseAddress(true);
return true;
} catch (IOException e) {
return false;
}
}
public static boolean isHostReachable(String host, int timeout) {
try {
InetAddress address = InetAddress.getByName(host);
return address.isReachable(timeout);
} catch (IOException e) {
return false;
}
}
public static String getHostname() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
return "unknown";
}
}
public static void main(String[] args) throws SocketException {
System.out.println("主机名: " + getHostname());
System.out.println("本机IP: " + getLocalIPAddress());
System.out.println("所有IP: " + getAllIPAddresses());
System.out.println("MAC地址: " + getMACAddress());
System.out.println("端口8080可用: " + isPortAvailable(8080));
System.out.println("localhost可达: " + isHostReachable("localhost", 1000));
}
}
五、总结 #
网络编程基础要点:
- 协议选择:根据应用需求选择TCP或UDP
- 资源管理:正确关闭Socket和网络资源
- 异常处理:处理网络中断和超时
- 线程安全:多线程环境下的数据同步
- 性能优化:使用NIO提高并发性能
下一章我们将学习MQTT协议,实现物联网消息通信。
最后更新:2026-03-27