Java进阶之旅-day05:网络编程

引言

在当今数字化的时代,网络编程在软件开发中扮演着至关重要的角色。Java 作为一门广泛应用的编程语言,提供了强大的网络编程能力。今天,我们深入学习了 Java 网络编程的基础知识,包括基本的通信架构、网络编程三要素、IP 地址、TCP 协议、UDP 通信等内容。接下来,我们将对这些知识点进行详细的总结。

基本的通信架构

在网络编程中,常见的通信架构有客户端 - 服务器(Client - Server,C/S)架构和浏览器 - 服务器(Browser - Server,B/S)架构。

C/S 架构

客户端 - 服务器架构是一种传统的网络通信模式。在这种架构中,客户端程序向服务器发送请求,服务器接收到请求后进行处理,并将处理结果返回给客户端。例如,我们使用的 QQ、微信等即时通讯软件就是典型的 C/S 架构应用。以下是一个简单的 C/S 架构 Java 示例,模拟客户端向服务器发送消息:

java 复制代码
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

// 服务器端
class SimpleServer {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(12345)) {
            System.out.println("Server is listening on port 12345");
            Socket socket = serverSocket.accept();
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String message = in.readLine();
            System.out.println("Received from client: " + message);
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// 客户端
class SimpleClient {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 12345);
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
            String message = "Hello, Server!";
            out.println(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

B/S 架构

浏览器 - 服务器架构是一种基于 Web 技术的网络通信模式。在这种架构中,客户端只需要通过浏览器访问服务器上的网页,服务器将网页内容返回给浏览器进行显示。例如,我们日常使用的各种网站就是 B/S 架构的应用。以下是一个简单的 Java Servlet 示例模拟 B/S 架构的服务器端处理:

java 复制代码
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html><body>");
        out.println("<h1>Hello, World!</h1>");
        out.println("</body></html>");
    }
}

网络编程三要素

网络编程的三要素包括 IP 地址、端口号和协议。

IP 地址

IP 地址是互联网协议地址的缩写,它是用于标识网络中设备的唯一标识符。通过 IP 地址,不同设备之间可以进行通信。

端口号

端口号是用于标识应用程序的数字。在一台设备上,可能同时运行着多个应用程序,每个应用程序通过不同的端口号来接收和发送数据。端口号的范围是 0 - 65535,其中 0 - 1023 通常被系统保留使用。

协议

协议是网络通信中双方必须遵循的规则和约定。常见的网络协议有 TCP(传输控制协议)和 UDP(用户数据报协议),我们将在后面详细介绍这两种协议。

IP 地址详解

IP 地址的作用

IP 地址的主要作用是在网络中唯一标识一台设备,使得不同设备之间能够进行通信。就像我们的家庭地址一样,通过 IP 地址,数据可以准确地从源设备传输到目标设备。

IP 地址的分类

IP 地址主要分为 IPv4 和 IPv6 两种类型。

IPv4

IPv4 是目前广泛使用的 IP 地址版本,它由 32 位二进制数组成,通常用点分十进制表示,例如 192.168.1.1。由于 IPv4 地址空间有限,随着互联网的发展,IPv4 地址已经逐渐耗尽。

IPv6

IPv6 是为了解决 IPv4 地址不足的问题而推出的新一代 IP 地址版本。它由 128 位二进制数组成,采用冒号十六进制表示,例如 2001:0db8:85a3:0000:0000:8a2e:0370:7334。IPv6 提供了巨大的地址空间,可以满足未来互联网发展的需求。

公网 IP 和 内网 IP

公网 IP

公网 IP 是可以直接在互联网上访问的 IP 地址。每个公网 IP 地址在全球范围内都是唯一的。通常,企业、机构和互联网服务提供商(ISP)会拥有公网 IP 地址。

内网 IP

内网 IP 是用于局域网内部通信的 IP 地址。内网 IP 地址在局域网内部是唯一的,但在不同的局域网中可以重复使用。常见的内网 IP 地址段有 10.0.0.0 - 10.255.255.255172.16.0.0 - 172.31.255.255192.168.0.0 - 192.168.255.255

查看本机 IP 地址

Windows 系统

在 Windows 系统中,可以通过以下步骤查看本机 IP 地址:

  1. 打开命令提示符(CMD)。
  2. 在命令提示符中输入 ipconfig 命令,按下回车键。
  3. 在输出结果中,可以找到本机的 IP 地址信息。
Linux 系统

在 Linux 系统中,可以通过以下命令查看本机 IP 地址:

java 复制代码
ifconfig
macOS 系统

在 macOS 系统中,可以通过以下步骤查看本机 IP 地址:

  1. 打开 "系统偏好设置"。
  2. 点击 "网络"。
  3. 在左侧列表中选择当前连接的网络,右侧会显示本机的 IP 地址信息。

查看是否与对方互通

可以使用 ping 命令来测试是否与对方设备互通。在命令提示符或终端中输入以下命令:

java 复制代码
ping 对方 IP 地址

如果能够收到对方设备的响应,表示与对方设备互通;如果无法收到响应,则可能存在网络连接问题。

本机 IP

本机 IP 是指当前设备在网络中的 IP 地址。在局域网中,本机 IP 通常是内网 IP 地址;如果设备直接连接到互联网,则本机 IP 是公网 IP 地址。

TCP 协议特点

TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层协议。它具有以下特点:

面向连接

在进行数据传输之前,TCP 会先建立连接,确保双方设备都处于可用状态。连接建立后,双方可以进行数据传输,传输完成后,再关闭连接。

可靠传输

TCP 通过确认机制、重传机制和滑动窗口机制等保证数据的可靠传输。如果发送方发送的数据没有收到接收方的确认信息,发送方会重新发送该数据。

字节流传输

TCP 将应用层的数据看作是无结构的字节流进行传输,接收方需要根据应用层的协议来解析这些字节流。

拥塞控制

TCP 具有拥塞控制机制,当网络出现拥塞时,TCP 会自动调整发送数据的速率,以避免网络拥塞进一步恶化。

UDP 通信

UDP(用户数据报协议)是一种无连接的、不可靠的传输层协议。与 TCP 不同,UDP 在进行数据传输之前不需要建立连接,也不保证数据的可靠传输。UDP 的特点是传输速度快、开销小,适用于对实时性要求较高、对数据准确性要求相对较低的应用场景,例如视频直播、音频通话等。

以下是一个简单的 Java UDP 通信示例:

java 复制代码
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

// UDP 发送端
class UDPSender {
    public static void main(String[] args) throws IOException {
        // 创建 DatagramSocket 对象
        DatagramSocket socket = new DatagramSocket();

        // 要发送的数据
        String message = "Hello, UDP!";
        byte[] sendData = message.getBytes();

        // 目标地址和端口
        InetAddress address = InetAddress.getByName("localhost");
        int port = 8888;

        // 创建 DatagramPacket 对象
        DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, address, port);

        // 发送数据
        socket.send(sendPacket);

        // 关闭套接字
        socket.close();
    }
}

// UDP 接收端
class UDPReceiver {
    public static void main(String[] args) throws IOException {
        // 创建 DatagramSocket 对象,并指定端口号
        DatagramSocket socket = new DatagramSocket(8888);

        // 创建接收数据的缓冲区
        byte[] receiveData = new byte[1024];

        // 创建 DatagramPacket 对象
        DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);

        // 接收数据
        socket.receive(receivePacket);

        // 解析接收到的数据
        String message = new String(receivePacket.getData(), 0, receivePacket.getLength());
        System.out.println("Received: " + message);

        // 关闭套接字
        socket.close();
    }
}

TCP 通信

TCP 通信是一种面向连接的通信方式,需要先建立连接,再进行数据传输,最后关闭连接。以下是一个简单的 Java TCP 通信示例:

java 复制代码
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

// TCP 服务器端
class TCPServer {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(9999)) {
            System.out.println("Server is listening on port 9999...");
            // 等待客户端连接
            Socket socket = serverSocket.accept();
            System.out.println("Client connected: " + socket.getInetAddress());

            // 获取输入流
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            // 获取输出流
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

            // 读取客户端发送的数据
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                System.out.println("Received from client: " + inputLine);
                // 向客户端发送响应
                out.println("Server received: " + inputLine);
            }

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

// TCP 客户端
class TCPClient {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 9999);
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) {

            String userInput;
            while ((userInput = stdIn.readLine()) != null) {
                // 向服务器发送数据
                out.println(userInput);
                // 读取服务器的响应
                String response = in.readLine();
                System.out.println("Received from server: " + response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

综合案例

假设我们要实现一个简单的文件传输系统,客户端将本地文件发送给服务器,服务器接收文件并保存到本地。以下是一个基于 TCP 协议的文件传输系统的示例代码:

java 复制代码
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

// 文件传输服务器端
class FileTransferServer {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(12345)) {
            System.out.println("Server is listening on port 12345...");
            // 等待客户端连接
            Socket socket = serverSocket.accept();
            System.out.println("Client connected: " + socket.getInetAddress());

            // 获取输入流
            InputStream in = socket.getInputStream();
            // 创建文件输出流
            FileOutputStream fos = new FileOutputStream("received_file.txt");

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }

            // 关闭流和连接
            fos.close();
            in.close();
            socket.close();
            System.out.println("File received successfully.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// 文件传输客户端
class FileTransferClient {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 12345);
             FileInputStream fis = new FileInputStream("test_file.txt");
             OutputStream out = socket.getOutputStream()) {

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }

            // 关闭流和连接
            fis.close();
            out.close();
            socket.close();
            System.out.println("File sent successfully.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

总结

通过今天的学习,我们对 Java 网络编程有了更深入的了解。掌握了基本的通信架构、网络编程三要素、IP 地址、TCP 协议和 UDP 通信等基础知识,并通过实际的代码示例加深了对这些知识的理解和应用。网络编程是 Java 开发中非常重要的一部分,在实际项目中有着广泛的应用,我们需要不断学习和实践,才能更好地掌握这门技术。

相关推荐
侠客行03178 小时前
Mybatis连接池实现及池化模式
java·mybatis·源码阅读
蛇皮划水怪8 小时前
深入浅出LangChain4J
java·langchain·llm
灰子学技术10 小时前
go response.Body.close()导致连接异常处理
开发语言·后端·golang
老毛肚10 小时前
MyBatis体系结构与工作原理 上篇
java·mybatis
风流倜傥唐伯虎10 小时前
Spring Boot Jar包生产级启停脚本
java·运维·spring boot
二十雨辰10 小时前
[python]-AI大模型
开发语言·人工智能·python
Yvonne爱编码10 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
Re.不晚10 小时前
JAVA进阶之路——无奖问答挑战1
java·开发语言
你这个代码我看不懂10 小时前
@ConditionalOnProperty不直接使用松绑定规则
java·开发语言
chian-ocean10 小时前
深入 CANN:使用 `tbe-op` 构建自定义高性能算子
网络