Java网络编程:让你的程序学会“打电话“的神奇技能

当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. 服务端实现流程

ServerClient创建ServerSocket绑定端口(bind)监听连接(listen)发起连接(connect)接受连接(accept)发送数据返回响应关闭连接ServerClient

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通信模型

DatagramPacket
DatagramPacket
Sender
Network
Receiver

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客户端比较

客户端类型引入版本特点示例类
HttpURLConnectionJava 1.1基础功能java.net.HttpURLConnection
HttpClientJava 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或异步IO2-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. 开发测试工具集

工具用途示例命令
telnetTCP连接测试telnet localhost 8080
nc (netcat)通用网络工具nc -l 9090
tcpdump网络抓包tcpdump port 80 -w capture.pcap
Wireshark协议分析图形化界面

十一、企业级应用架构

1. 高并发服务设计

客户端
负载均衡
服务节点1
服务节点2
服务节点3
数据库集群

2. 微服务通信模式

// Feign客户端示例
@FeignClient(name = "user-service")
public interface UserClient {
    @GetMapping("/users/{id}")
    User getUser(@PathVariable Long id);
}

// 使用示例
User user = userClient.getUser(123L);

结语:打开网络世界的大门

🔑 网络编程三要素

  1. 找对人(IP+端口)
  2. 说对话(协议格式)
  3. 守规矩(开闭资源)

💡 记住这个口诀:

网络编程不神秘,IP端口要记牢;
TCP可靠像电话,UDP快速像电报;
HTTP就像寄信件,数据格式很重要;
资源关闭不能忘,安全加密更可靠!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农技术栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值