当Java程序开始"社交"
想象你的程序是一个宅男:
📞 没有网络 → 只能自言自语(单机程序)
🌐 有了网络编程 → 可以给其他电脑"打电话"(通信)
Java网络编程就是教你的程序如何通过网线"交朋友"的黑科技!今天我们就来揭开它的神秘面纱~
一、网络编程基础:IP地址和端口号
1. 网络通信核心要素
2. 计算机世界的"电话号码"
// IP地址就像手机号
InetAddress address = InetAddress.getByName("www.baidu.com");
// 端口号就像分机号
int port = 80; // HTTP默认端口
3. 关键协议对比
协议 | 可靠性 | 连接方式 | 速度 | 典型应用 |
---|---|---|---|---|
TCP | 高 | 面向连接 | 较慢 | 文件传输、网页浏览 |
UDP | 低 | 无连接 | 快 | 视频会议、DNS查询 |
HTTP | 基于TCP | 请求-响应 | 中等 | Web API调用 |
二、TCP编程:可靠的"电话连线"
1. 服务端实现流程
2. 服务端(接电话的人)
// 创建服务端(绑定端口)
ServerSocket server = new ServerSocket(8888);
System.out.println("等待来电...");
// 等待客户端连接
Socket client = server.accept(); // 这里会阻塞
System.out.println(client.getInetAddress() + "来电了!");
// 获取输入输出流
BufferedReader in = new BufferedReader(
new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream(), true);
// 读取客户端消息
String msg = in.readLine();
System.out.println("客户端说:" + msg);
// 回复客户端
out.println("你好,我是Java服务端");
// 挂电话
client.close();
server.close();
3. 客户端(打电话的人)
// 连接服务端
Socket socket = new Socket("127.0.0.1", 8888);
// 获取输入输出流
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);
// 挂电话
socket.close();
4. 完整服务端代码
public class TcpServer {
public static void main(String[] args) throws IOException {
try (ServerSocket server = new ServerSocket(8080)) {
System.out.println("Server started on port 8080");
while (true) {
Socket client = server.accept();
new Thread(() -> handleClient(client)).start();
}
}
}
private static void handleClient(Socket client) {
try (BufferedReader in = new BufferedReader(
new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(
client.getOutputStream(), true)) {
String request;
while ((request = in.readLine()) != null) {
System.out.println("Received: " + request);
out.println("Echo: " + request);
}
} catch (IOException e) {
System.err.println("Client handling error: " + e.getMessage());
} finally {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
三、UDP编程:快速的"对讲机"
1. UDP通信模型
2. UDP文件传输示例
// 发送方
public class UdpSender {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket();
byte[] fileData = Files.readAllBytes(Paths.get("test.txt"));
DatagramPacket packet = new DatagramPacket(
fileData, fileData.length,
InetAddress.getByName("localhost"), 9090);
socket.send(packet);
System.out.println("File sent successfully");
socket.close();
}
}
// 接收方
public class UdpReceiver {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(9090);
byte[] buffer = new byte[65535];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);
Files.write(Paths.get("received.txt"),
Arrays.copyOf(packet.getData(), packet.getLength()));
System.out.println("File saved successfully");
socket.close();
}
}
3. 发送方
// 创建UDP套接字
DatagramSocket socket = new DatagramSocket();
// 准备数据包
String msg = "UDP消息测试";
byte[] data = msg.getBytes();
DatagramPacket packet = new DatagramPacket(
data, data.length,
InetAddress.getByName("localhost"), 9999);
// 发送
socket.send(packet);
System.out.println("消息已发送");
// 关闭
socket.close();
4. 接收方
// 创建UDP套接字(绑定端口)
DatagramSocket socket = new DatagramSocket(9999);
// 准备接收缓冲区
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
// 接收数据(阻塞等待)
socket.receive(packet);
String msg = new String(packet.getData(), 0, packet.getLength());
System.out.println("收到来自" + packet.getAddress() + "的消息:" + msg);
// 关闭
socket.close();
四、HTTP编程:与网页"对话"
1. Java原生HTTP客户端比较
客户端类型 | 引入版本 | 特点 | 示例类 |
---|---|---|---|
HttpURLConnection | Java 1.1 | 基础功能 | java.net.HttpURLConnection |
HttpClient | Java 11 | 异步支持 | java.net.http.HttpClient |
2. HttpClient高级用法
public class AdvancedHttpClient {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(5))
.followRedirects(HttpClient.Redirect.NORMAL)
.build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.timeout(Duration.ofSeconds(10))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(
"{\"name\":\"John\",\"age\":30}"))
.build();
CompletableFuture<HttpResponse<String>> future =
client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
future.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();
}
}
3. 使用HttpURLConnection
URL url = new URL("http://www.example.com");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 设置请求方法
conn.setRequestMethod("GET");
// 获取响应
try (BufferedReader in = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) {
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
}
4. 使用HttpClient(Java11+)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/data"))
.build();
// 异步发送请求
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();
五、实战案例:简易聊天程序
1. 服务端代码
public class ChatServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(12345);
System.out.println("聊天室已启动...");
Socket client = server.accept();
new Thread(() -> handleClient(client)).start();
}
static void handleClient(Socket client) {
try (BufferedReader in = new BufferedReader(
new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream(), true)) {
String input;
while ((input = in.readLine()) != null) {
System.out.println("客户端: " + input);
out.println("服务器回复: " + input.toUpperCase());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. 客户端代码
public class ChatClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost", 12345);
new Thread(() -> {
try (BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()))) {
String response;
while ((response = in.readLine()) != null) {
System.out.println(response);
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
try (PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader console = new BufferedReader(
new InputStreamReader(System.in))) {
String userInput;
while ((userInput = console.readLine()) != null) {
out.println(userInput);
}
}
}
}
六、网络编程高级主题
1. 非阻塞NIO编程
public class NioServer {
public static void main(String[] args) throws IOException {
ServerSocketChannel server = ServerSocketChannel.open();
server.bind(new InetSocketAddress(8080));
server.configureBlocking(false);
Selector selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
for (SelectionKey key : keys) {
if (key.isAcceptable()) {
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
}
if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
client.read(buffer);
// 处理数据...
}
}
keys.clear();
}
}
}
2. 网络性能优化技巧
优化方向 | 具体措施 | 效果提升 |
---|---|---|
连接池 | 复用TCP连接 | 30%-50% |
缓冲区 | 调整Socket缓冲区大小 | 10%-20% |
线程模型 | 使用NIO或异步IO | 2-3倍 |
数据压缩 | 启用GZIP压缩 | 40%-70% |
七、网络编程五大坑点
1. 忘记关闭连接
// 错误示范(资源泄露)
Socket socket = new Socket(...);
// 使用后没close()
// 正确做法(try-with-resources)
try (Socket socket = new Socket(...)) {
// 使用socket
}
2. 阻塞问题
// 设置超时避免无限等待
socket.setSoTimeout(5000); // 5秒超时
3. 乱码问题
// 指定编码格式
new InputStreamReader(socket.getInputStream(), "UTF-8");
4. 端口占用
// 检查端口是否可用
try (ServerSocket test = new ServerSocket(port)) {
// 端口可用
} catch (IOException e) {
// 端口被占用
}
5. 防火墙拦截
# Linux开放端口
sudo ufw allow 8080/tcp
八、安全升级:SSL加密通信
1. 创建SSLServerSocket
SSLServerSocketFactory ssf = (SSLServerSocketFactory)
SSLServerSocketFactory.getDefault();
SSLServerSocket server = (SSLServerSocket)
ssf.createServerSocket(8443);
2. SSL/TLS配置示例
public class SslServer {
public static void main(String[] args) throws Exception {
SSLContext context = SSLContext.getInstance("TLS");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream("server.p12"), "password".toCharArray());
kmf.init(ks, "password".toCharArray());
context.init(kmf.getKeyManagers(), null, null);
SSLServerSocketFactory factory = context.getServerSocketFactory();
SSLServerSocket server = (SSLServerSocket) factory.createServerSocket(8443);
System.out.println("SSL server started");
Socket client = server.accept();
// 处理客户端...
}
}
3. HTTPS客户端
HttpsURLConnection conn = (HttpsURLConnection)
new URL("https://example.com").openConnection();
conn.setHostnameVerifier((hostname, session) -> true); // 简化验证
九、常见问题解决方案
1. 连接超时问题排查
// 设置连接超时
Socket socket = new Socket();
socket.connect(new InetSocketAddress("host", port), 5000); // 5秒超时
// 设置读取超时
socket.setSoTimeout(3000); // 3秒读取超时
2. 大文件传输优化
// 使用零拷贝技术传输文件
try (FileChannel source = FileChannel.open(Paths.get("bigfile.iso"));
SocketChannel socket = SocketChannel.open(
new InetSocketAddress("remote", 9090))) {
source.transferTo(0, source.size(), socket);
}
十、网络调试工具推荐
1. 开发测试工具集
工具 | 用途 | 示例命令 |
---|---|---|
telnet | TCP连接测试 | telnet localhost 8080 |
nc (netcat) | 通用网络工具 | nc -l 9090 |
tcpdump | 网络抓包 | tcpdump port 80 -w capture.pcap |
Wireshark | 协议分析 | 图形化界面 |
十一、企业级应用架构
1. 高并发服务设计
2. 微服务通信模式
// Feign客户端示例
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/users/{id}")
User getUser(@PathVariable Long id);
}
// 使用示例
User user = userClient.getUser(123L);
结语:打开网络世界的大门
🔑 网络编程三要素:
- 找对人(IP+端口)
- 说对话(协议格式)
- 守规矩(开闭资源)
💡 记住这个口诀:
网络编程不神秘,IP端口要记牢;
TCP可靠像电话,UDP快速像电报;
HTTP就像寄信件,数据格式很重要;
资源关闭不能忘,安全加密更可靠!