Day-05 Java 网络编程详细知识

发布于:2025-04-13 ⋅ 阅读:(25) ⋅ 点赞:(0)

目录

一、引言

二、网络编程基础概念

2.1 网络协议

2.2 IP 地址和端口号

三、Java 中的网络编程类库

3.1 java.net 包

3.2 java.nio 包

四、常见应用场景

4.1 文件传输

4.2 网页爬虫

五、总结

一、引言

在当今数字化时代,网络编程是软件开发中不可或缺的一部分。Java 作为一种广泛使用的编程语言,提供了强大而丰富的网络编程功能。通过 Java 网络编程,开发者可以创建各种网络应用程序,如客户端 - 服务器应用、网络爬虫、即时通讯工具等。本文将详细介绍 Java 网络编程的基础知识和常见应用。

二、网络编程基础概念

2.1 网络协议

网络协议是计算机之间进行通信的规则和约定。常见的网络协议有 TCP(传输控制协议)和 UDP(用户数据报协议)。

  • TCP:是一种面向连接的、可靠的、基于字节流的传输层通信协议。它在传输数据前需要建立连接,传输过程中保证数据的顺序和完整性,传输完成后需要关闭连接。常用于对数据准确性要求较高的场景,如文件传输、网页浏览等。
  • UDP:是一种无连接的传输层协议,它不保证数据的可靠传输,也不保证数据的顺序。但 UDP 具有传输速度快、开销小的特点,常用于对实时性要求较高的场景,如视频会议、在线游戏等。

2.2 IP 地址和端口号

  • IP 地址:是用于标识网络中设备的唯一标识符。IPv4 地址由 32 位二进制数组成,通常表示为点分十进制形式,如 192.168.1.1。IPv6 地址由 128 位二进制数组成,用于解决 IPv4 地址枯竭的问题。
  • 端口号:是一个 16 位的整数,用于标识同一台设备上的不同应用程序或服务。端口号的范围是 0 - 65535,其中 0 - 1023 是系统保留端口,通常用于一些知名的服务,如 HTTP 服务使用端口 80,HTTPS 服务使用端口 443。

三、Java 中的网络编程类库

3.1 java.net 包

Java 的 java.net 包提供了网络编程所需的基本类和接口,主要包括以下几类:

  • InetAddress 类:用于表示 IP 地址,提供了获取本地和远程主机 IP 地址的方法。
import java.net.InetAddress;
import java.net.UnknownHostException;

public class InetAddressExample {
    public static void main(String[] args) {
        try {
            // 获取本地主机的 InetAddress 对象
            InetAddress localHost = InetAddress.getLocalHost();
            System.out.println("本地主机名: " + localHost.getHostName());
            System.out.println("本地主机 IP 地址: " + localHost.getHostAddress());

            // 获取指定域名的 InetAddress 对象
            InetAddress google = InetAddress.getByName("www.google.com");
            System.out.println("Google 主机名: " + google.getHostName());
            System.out.println("Google 主机 IP 地址: " + google.getHostAddress());
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }
}
  • Socket 类和 ServerSocket 类:用于实现基于 TCP 的网络通信。Socket 类表示客户端套接字,ServerSocket 类表示服务器端套接字。
// 服务器端代码
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TCPServer {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8888)) {
            System.out.println("服务器已启动,等待客户端连接...");
            Socket socket = serverSocket.accept();
            System.out.println("客户端已连接: " + socket.getInetAddress());

            // 获取输入流
            InputStream inputStream = socket.getInputStream();
            byte[] buffer = new byte[1024];
            int length = inputStream.read(buffer);
            String message = new String(buffer, 0, length);
            System.out.println("收到客户端消息: " + message);

            // 获取输出流,向客户端发送消息
            OutputStream outputStream = socket.getOutputStream();
            String response = "服务器已收到消息: " + message;
            outputStream.write(response.getBytes());

            // 关闭连接
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// 客户端代码
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class TCPClient {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 8888)) {
            // 获取输出流,向服务器发送消息
            OutputStream outputStream = socket.getOutputStream();
            String message = "Hello, Server!";
            outputStream.write(message.getBytes());

            // 获取输入流,接收服务器响应
            InputStream inputStream = socket.getInputStream();
            byte[] buffer = new byte[1024];
            int length = inputStream.read(buffer);
            String response = new String(buffer, 0, length);
            System.out.println("收到服务器响应: " + response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • DatagramSocket 类和 DatagramPacket 类:用于实现基于 UDP 的网络通信。DatagramSocket 类表示数据报套接字,DatagramPacket 类表示数据报包。
// 服务器端代码
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPServer {
    public static void main(String[] args) {
        try (DatagramSocket socket = new DatagramSocket(9999)) {
            byte[] receiveBuffer = new byte[1024];
            DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
            System.out.println("服务器已启动,等待客户端消息...");
            socket.receive(receivePacket);
            String message = new String(receivePacket.getData(), 0, receivePacket.getLength());
            System.out.println("收到客户端消息: " + message);

            // 向客户端发送响应
            String response = "服务器已收到消息: " + message;
            byte[] sendBuffer = response.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length,
                    receivePacket.getAddress(), receivePacket.getPort());
            socket.send(sendPacket);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// 客户端代码
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPClient {
    public static void main(String[] args) {
        try (DatagramSocket socket = new DatagramSocket()) {
            InetAddress serverAddress = InetAddress.getByName("localhost");
            String message = "Hello, Server!";
            byte[] sendBuffer = message.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length, serverAddress, 9999);
            socket.send(sendPacket);

            // 接收服务器响应
            byte[] receiveBuffer = new byte[1024];
            DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
            socket.receive(receivePacket);
            String response = new String(receivePacket.getData(), 0, receivePacket.getLength());
            System.out.println("收到服务器响应: " + response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3.2 java.nio 包

Java 的 java.nio 包(New I/O)提供了非阻塞 I/O 操作,提高了网络编程的性能和效率。主要包括 SelectorSocketChannelServerSocketChannel 等类。

// 服务器端代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioServer {
    public static void main(String[] args) {
        try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
            serverSocketChannel.socket().bind(new InetSocketAddress(7777));
            serverSocketChannel.configureBlocking(false);

            Selector selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            System.out.println("服务器已启动,等待客户端连接...");

            while (true) {
                int readyChannels = selector.select();
                if (readyChannels == 0) continue;

                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();

                    if (key.isAcceptable()) {
                        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                        SocketChannel socketChannel = serverChannel.accept();
                        socketChannel.configureBlocking(false);
                        socketChannel.register(selector, SelectionKey.OP_READ);
                        System.out.println("客户端已连接: " + socketChannel.getRemoteAddress());
                    } else if (key.isReadable()) {
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        int bytesRead = socketChannel.read(buffer);
                        if (bytesRead > 0) {
                            buffer.flip();
                            byte[] data = new byte[buffer.remaining()];
                            buffer.get(data);
                            String message = new String(data);
                            System.out.println("收到客户端消息: " + message);

                            // 向客户端发送响应
                            String response = "服务器已收到消息: " + message;
                            ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());
                            socketChannel.write(responseBuffer);
                        }
                    }

                    keyIterator.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// 客户端代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class NioClient {
    public static void main(String[] args) {
        try (SocketChannel socketChannel = SocketChannel.open()) {
            socketChannel.connect(new InetSocketAddress("localhost", 7777));
            socketChannel.configureBlocking(false);

            String message = "Hello, Server!";
            ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
            socketChannel.write(buffer);

            ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);
            int bytesRead = socketChannel.read(receiveBuffer);
            if (bytesRead > 0) {
                receiveBuffer.flip();
                byte[] data = new byte[receiveBuffer.remaining()];
                receiveBuffer.get(data);
                String response = new String(data);
                System.out.println("收到服务器响应: " + response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

四、常见应用场景

4.1 文件传输

可以使用 Java 的网络编程功能实现文件的传输。客户端将文件读取到内存中,然后通过网络发送给服务器;服务器接收文件数据并保存到本地。

// 服务器端代码
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class FileServer {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(5555)) {
            System.out.println("服务器已启动,等待客户端连接...");
            Socket socket = serverSocket.accept();
            System.out.println("客户端已连接: " + socket.getInetAddress());

            InputStream inputStream = socket.getInputStream();
            FileOutputStream fileOutputStream = new FileOutputStream("received_file.txt");

            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                fileOutputStream.write(buffer, 0, bytesRead);
            }

            fileOutputStream.close();
            inputStream.close();
            socket.close();
            System.out.println("文件接收完成");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// 客户端代码
import java.io.*;
import java.net.Socket;

public class FileClient {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 5555);
             FileInputStream fileInputStream = new FileInputStream("test_file.txt");
             OutputStream outputStream = socket.getOutputStream()) {

            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }

            outputStream.flush();
            System.out.println("文件发送完成");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4.2 网页爬虫

网页爬虫是一种自动获取网页内容的程序。可以使用 Java 的网络编程功能发送 HTTP 请求,获取网页的 HTML 内容,然后进行解析和处理。

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class WebCrawler {
    public static void main(String[] args) {
        try {
            URL url = new URL("https://www.example.com");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");

            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line;
            StringBuilder content = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                content.append(line);
            }
            reader.close();

            System.out.println("网页内容: " + content.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

五、总结

Java 网络编程提供了丰富的类库和功能,开发者可以根据不同的需求选择合适的网络协议和编程方式。通过掌握 Java 网络编程的基础知识和常见应用,开发者可以创建出高效、稳定的网络应用程序。同时,在实际开发中,还需要考虑网络安全、性能优化等方面的问题,以确保应用程序的质量和可靠性。