Linux编程之socket入门教程 socket通讯原理
在Linux网络编程中,套接字Socket是进程间通信的基础,用来在网络上不同主机间进行数据的发送和接收。套接字作为一种抽象的接口,它屏蔽了底层网络协议的复杂性,使得开发者可以专注于数据的传输。以下将详细介绍Linux网络编程中的Socket,及其相关操作和函数。
客户端 服务器端
┌─────────────┐ ┌─────────────┐
│ 1. 创建Socket │ <────连接请求────── │ 1. 创建Socket │
└─────────────┘ └─────────────┘│ ││ │
┌─────────────┐ ┌─────────────┐
│ 2. 连接服务器 │─────连接确认──────> │ 2. 绑定端口 │
└─────────────┘ └─────────────┘│ ││ │
┌─────────────┐ ┌─────────────┐
│ 3. 发送数据 │──────数据传输───────> │ 3. 监听连接 │
└─────────────┘ └─────────────┘│ ││ │
┌─────────────┐ ┌─────────────┐
│ 4. 接收数据 │ <────响应数据────── │ 4. 接收数据 │
└─────────────┘ └─────────────┘│ │▼ ▼关闭连接 关闭连接
1. Socket的类型
套接字根据使用的协议和功能,分为以下几类:
- 流式套接字(SOCK_STREAM):使用TCP协议,面向连接,提供可靠的数据传输,保证数据的顺序性。
- 数据报套接字(SOCK_DGRAM):使用UDP协议,无连接,不保证数据顺序和完整性,但效率较高。
- 原始套接字(SOCK_RAW):允许对IP包进行底层操作,通常用于网络开发和调试。
2. Socket编程中的基本流程
无论是使用TCP还是UDP,Socket编程的一般步骤都是类似的。通常包括以下操作:
- 创建Socket
- 绑定地址
- 监听/连接
- 发送/接收数据
- 关闭Socket
常用的Socket函数以及各个函数的详细用法:
socket()
: 创建套接字,返回套接字的文件描述符。bind()
: 将套接字与本地IP地址和端口号绑定。listen()
: 服务器端监听来自客户端的连接请求(仅用于TCP)。accept()
: 服务器端接受客户端的连接(仅用于TCP)。connect()
: 客户端与服务器建立连接(仅用于TCP)。send()
: 发送数据。recv()
: 接收数据。sendto()
: 发送数据到指定的地址(用于UDP)。recvfrom()
: 从指定的地址接收数据(用于UDP)。close()
: 关闭套接字。
a. socket()
- 创建套接字
函数原型:
int socket(int domain, int type, int protocol);
参数:
domain
:协议族AF_INET
:IPv4。AF_INET6
:IPv6。AF_UNIX
:本地主机通信。
type
:套接字类型SOCK_STREAM
:TCP流式套接字。SOCK_DGRAM
:UDP数据报套接字。SOCK_RAW
:原始套接字。
protocol
:协议号,通常为0
(自动选择)。
返回值:
- 成功:返回套接字文件描述符。
- 失败:返回
-1
。
示例:
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
b. bind()
- 绑定套接字到地址
函数原型:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数:
sockfd
:套接字文件描述符。addr
:要绑定的IP地址和端口号。addrlen
:地址结构长度。
返回值:
- 成功:返回
0
。 - 失败:返回
-1
。
示例:
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);bind(sockfd, (struct sockaddr *)&address, sizeof(address));
c. listen()
- 监听连接请求
函数原型:
int listen(int sockfd, int backlog);
参数:
sockfd
:套接字文件描述符(TCP)。backlog
:未决连接的队列长度。
返回值:
- 成功:返回
0
。 - 失败:返回
-1
。
示例:
listen(sockfd, 5);
d. accept()
- 接受连接请求
函数原型:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数:
sockfd
:监听的套接字。addr
:存储客户端的地址。addrlen
:地址结构的长度。
返回值:
- 成功:返回新的套接字文件描述符。
- 失败:返回
-1
。
示例:
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
int new_socket = accept(sockfd, (struct sockaddr *)&client_addr, &addrlen);
e. connect()
- 发起连接请求
函数原型:
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数:
sockfd
:套接字文件描述符。addr
:服务器地址。addrlen
:地址结构长度。
返回值:
- 成功:返回
0
。 - 失败:返回
-1
。
示例:
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
f. send()
和 recv()
- 发送和接收数据
函数原型:
send()
:
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
recv()
:
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
参数:
sockfd
:套接字文件描述符。buf
:数据缓冲区。len
:缓冲区长度。flags
:操作标志(如0
)。
返回值:
- 成功:返回发送/接收的字节数。
- 失败:返回
-1
。
示例:
char buffer[1024] = "Hello, Server!";
send(sockfd, buffer, strlen(buffer), 0);
recv(sockfd, buffer, 1024, 0);
g. sendto()
和 recvfrom()
- 发送和接收数据报(用于UDP)
函数原型:
sendto()
:
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
recvfrom()
:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
参数:
sockfd
:套接字文件描述符。buf
:数据缓冲区。len
:缓冲区长度。flags
:操作标志(如0
)。dest_addr
:目标地址(用于sendto()
)。addrlen
:地址结构长度。
返回值:
- 成功:返回发送/接收的字节数。
- 失败:返回
-1
。
示例:
char buffer[1024] = "Hello, UDP Server!";
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
recvfrom(sockfd, buffer, 1024, 0, (struct sockaddr *)&server_addr, &addrlen);
h. close()
- 关闭套接字
函数原型:
int close(int sockfd);
参数:
sockfd
:要关闭的套接字文件描述符。
返回值:
- 成功:返回
0
。 - 失败:返回
-1
。
示例:
close(sockfd);
i. shutdown()
- 部分关闭套接字
函数原型:
int shutdown(int sockfd, int how);
参数:
sockfd
:套接字文件描述符。how
:关闭操作:SHUT_RD
:关闭读操作。SHUT_WR
:关闭写操作。SHUT_RDWR
:同时关闭读写操作。
返回值:
- 成功:返回
0
。 - 失败:返回
-1
。
示例:
shutdown(sockfd, SHUT_WR);
这些函数为Linux网络编程中的Socket操作提供了基础。
3. 示例代码
下面是一个简单的基于Socket编程的网络通信实例,包含服务器端和客户端。该示例使用TCP协议,服务器接收来自客户端的消息并返回响应。
服务器端代码 (server.c)
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>#define PORT 8080int main() {int server_fd, new_socket;struct sockaddr_in address;int addrlen = sizeof(address);char buffer[1024] = {0};const char *hello = "Hello from server";// 创建套接字if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("Socket failed");return 1;}// 绑定地址和端口address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("Bind failed");return 1;}// 开始监听if (listen(server_fd, 3) < 0) {perror("Listen failed");return 1;}printf("Server listening on port %d\n", PORT);// 接受客户端连接if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("Accept failed");return 1;}// 接收客户端消息int valread = read(new_socket, buffer, 1024);printf("Received from client: %s\n", buffer);// 发送响应给客户端send(new_socket, hello, strlen(hello), 0);printf("Hello message sent to client\n");// 关闭套接字close(new_socket);close(server_fd);return 0;
}
客户端代码 (client.c)
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>#define PORT 8080int main() {int sock = 0;struct sockaddr_in serv_addr;const char *hello = "Hello from client";char buffer[1024] = {0};// 创建套接字if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {printf("\nSocket creation error\n");return 1;}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(PORT);// 将服务器地址转换为二进制if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {printf("\nInvalid address or Address not supported\n");return 1;}// 连接服务器if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {printf("\nConnection Failed\n");return 1;}// 发送消息给服务器send(sock, hello, strlen(hello), 0);printf("Hello message sent\n");// 接收服务器的响应int valread = read(sock, buffer, 1024);printf("Received from server: %s\n", buffer);// 关闭套接字close(sock);return 0;
}
编译步骤
-
创建源文件:
- 将服务器代码保存为
server.c
,客户端代码保存为client.c
。
- 将服务器代码保存为
-
编译服务器端:
在终端中运行以下命令:gcc server.c -o server
-
编译客户端:
在终端中运行以下命令:gcc client.c -o client
运行步骤
-
启动服务器端:
在终端中运行以下命令,启动服务器端程序:./server
-
启动客户端:
在另一个终端中运行以下命令,启动客户端程序:./client
运行结果
-
服务器端输出:
Server listening on port 8080 Received from client: Hello from client Hello message sent to client
-
客户端输出:
Hello message sent Received from server: Hello from server
总结:
- 在这个例子中,服务器端在端口
8080
上监听客户端连接,接收到客户端的消息后,向客户端发送一条响应消息。 - 客户端连接到服务器并发送一条消息,随后接收到服务器的响应。
此实例展示了Socket编程的基本流程,涉及到套接字的创建、绑定、监听、连接、发送和接收数据等步骤。
4. Socket的优缺点
优点:
-
灵活性高:
- Socket提供了对网络通信底层的完全控制,适用于多种协议(TCP、UDP、原始套接字等)。
- 可以处理从低级别的二进制传输到高级别的应用协议,实现自定义网络通信需求。
-
跨平台支持:
- Socket API标准化,几乎所有操作系统都提供了对Socket编程的支持。
- 适用于大多数编程语言(C/C++、Python、Java等),可以在多平台上进行开发。
-
适用于各种场景:
- 无论是构建低延迟的实时应用(如视频会议、游戏),还是进行大规模分布式系统开发,Socket都能胜任。
- 支持同步、异步、非阻塞等多种编程模式。
-
高性能:
- 对于高性能需求场景(如高并发的服务器、流媒体等),Socket能够提供极高的效率,尤其是在与事件驱动的库(如
epoll
、select
、poll
)结合时。
- 对于高性能需求场景(如高并发的服务器、流媒体等),Socket能够提供极高的效率,尤其是在与事件驱动的库(如
缺点:
-
编程复杂度高:
- 使用Socket需要开发者理解网络协议、地址绑定、连接状态管理、错误处理等低层细节。
- 开发者需要手动处理数据包的组装、拆分以及超时等情况,代码复杂度较高。
-
缺乏应用层协议支持:
- Socket仅支持传输层协议(如TCP、UDP),不直接提供应用层协议(如HTTP、FTP)的支持。开发者需自行构建或使用其他库来实现这些协议。
- 如果需要处理复杂的应用协议,可能会导致额外的工作。
-
难以扩展:
- 对于大规模应用,Socket编程难以扩展和维护。需要手动处理并发问题,使用多线程或多进程模型,复杂性增加。
- 负载均衡、故障恢复等高级特性需要额外设计。
-
跨语言通信复杂:
- 虽然Socket本身是跨语言的,但对于不同语言间的通信,开发者必须在数据编码/解码上花费更多精力(如使用JSON、Protobuf等协议进行数据序列化)。
Socket与其他网络编程技术的对比
1. HTTP库(如libcurl
、requests
):
-
优点:
- 提供了高层次的抽象,简化了与Web服务器的交互(如处理GET、POST请求)。
- 内建了许多应用层功能(如自动重定向、Cookie管理、SSL加密)。
- 适合快速开发基于HTTP协议的客户端或服务器。
-
缺点:
- 只能处理HTTP协议,适用场景有限。
- 性能通常较低,不适合实时或高并发需求。
2. RPC框架(如gRPC、Thrift):
-
优点:
- 高层抽象,提供了远程过程调用功能,开发者只需关注业务逻辑。
- 支持多种语言、跨平台通信,内建序列化和高效通信协议(如Protobuf)。
- 自带负载均衡、认证等功能,适合构建微服务架构。
-
缺点:
- 配置复杂,初始开发成本较高。
- 不适合需要低延迟的实时通信场景。
3. 消息队列(如RabbitMQ、Kafka):
-
优点:
- 提供可靠的异步消息传递机制,适用于分布式系统中的消息传递和队列处理。
- 支持消息持久化、负载均衡和重试机制,减少数据丢失风险。
-
缺点:
- 通信延迟较大,不适合实时应用。
- 安装和维护较为复杂,特别是在集群环境中。
4. WebSocket:
-
优点:
- 提供全双工通信,适用于需要双向持续连接的应用(如即时聊天、股票行情推送)。
- 较Socket更加简单易用,特别适合Web应用。
-
缺点:
- 依赖于浏览器或特定的库,不如原生Socket灵活。
- 只支持在HTTP/HTTPS之上建立的连接,适用场景有限。
5. 高层框架(如Boost.Asio、Twisted、Node.js):
-
优点:
- 提供异步I/O和事件驱动模型,简化了Socket编程的复杂性。
- 内置了对定时器、文件I/O等功能的支持,可以实现高效的网络编程。
-
缺点:
- 框架本身的学习成本较高,特别是对复杂的异步操作需要深入理解。
- 封装较多,失去了一定的底层控制权。
总结:
技术 | 优点 | 缺点 |
---|---|---|
Socket | 灵活、跨平台、适合高并发、低延迟应用。 | 编程复杂、需要手动处理并发、应用层协议需要自行实现。 |
HTTP库 | 易用,处理HTTP协议快速高效。 | 仅限于HTTP协议,无法处理复杂通信场景。 |
RPC框架 | 高层抽象、跨语言、适合微服务架构。 | 初始复杂度高,不适合低延迟需求。 |
消息队列 | 异步通信、可靠性高、支持分布式系统。 | 延迟较大、适用场景有限。 |
WebSocket | 双向通信、适合Web应用、全双工模式。 | 场景有限、需要在HTTP/HTTPS上运行。 |
高层框架 | 提供异步和事件驱动模型,简化编程。 | 封装较多,失去一定的灵活性。 |
Socket适合对网络编程有更高控制需求、需要自定义协议或追求高性能的场景,而其他高层网络编程方式更适合简化开发、快速集成应用层协议的场合。
相关文章:

Linux编程之socket入门教程 socket通讯原理
在Linux网络编程中,套接字Socket是进程间通信的基础,用来在网络上不同主机间进行数据的发送和接收。套接字作为一种抽象的接口,它屏蔽了底层网络协议的复杂性,使得开发者可以专注于数据的传输。以下将详细介绍Linux网络编程中的So…...

Windows上安装RabbitMQ
rabbitmq是干嘛的我就不介绍了,直接开始安装教程。 搭建成功演示图 下载安装包 https://pan.baidu.com/s/1ZlCFxh9Q00ynSU3ZCpTC9Q?pwdry51pan.baidu.com/s/1ZlCFxh9Q00ynSU3ZCpTC9Q?pwdry51 下载完后有两个包(erlang和rabbitmq) 先安装otp_win64_24.1.7.exe…...

【C++ 高频面试题】构造函数和析构函数你了解多少呢?
文章目录 1. 什么是构造函数和析构函数2. 构造函数和析构函数可以是虚函数吗3. 构造函数有哪几种4. 深拷贝和浅拷贝的区别 1. 什么是构造函数和析构函数 🐧 构造函数: 构造函数是在创建对象时自动调用的特殊成员函数。 目的:初始化对象的成…...

linux中vim介绍以及常用命令大全
前言 在Linux系统中,Vim是一个功能强大的文本编辑器,它广泛应用于服务器管理、脚本编写和程序开发中。Vim拥有两种模式:命令模式和插入模式。了解和掌握常用的Vim命令对于提高文本编辑效率至关重要。本文将详细介绍Vim的常用命令,…...

线性代数 第六讲 特征值和特征向量_相似对角化_实对称矩阵_重点题型总结详细解析
文章目录 1.特征值和特征向量1.1 特征值和特征向量的定义1.2 特征值和特征向量的求法1.3 特征值特征向量的主要结论 2.相似2.1 相似的定义2.2 相似的性质2.3 相似的结论 3.相似对角化4.实对称矩阵4.1 实对称矩阵的基本性质4.2 施密特正交化 5.重难点题型总结5.1 判断矩阵能否相…...

CSS“多列布局”(补充)——WEB开发系列35
多列布局是一种非常常见的布局方式,适用于内容丰富的页面,如新闻网站、杂志或博客。 一、CSS多列布局概述 CSS多列布局允许我们将内容分成多个垂直列,使页面布局更加灵活和多样化。多列布局的主要属性包括 column-count、column…...

UI自动化测试痛点解决方案
前言 UI自动化测试可以快速、准确地执行大量的测试用例,减少人工测试所需的时间和劳动力。能够在短时间内完成多个测试用例的执行,提高测试的效率和速度。但是UI自动化有个最大的痛点。当前端界面发生变化时,往往页面元素定位也会改变&#…...

如何将QAD系统EDI模块无缝迁移到知行之桥?
什么是QAD系统? QAD(Quality, Applications, Development)系统,是专为制造业设计的一款ERP软件,主要包含供应链管理、生产管理、财务和客户管理等业务功能,这家公司1979年成立于美国,目前在汽车…...

Linux学习-ELK(一)
配置三台elasticsearch服务器 安装包 elasticsearch.j2 报错 #---执行rsync命令报以下错误 [rootes1 ~]# rsync -av /etc/hosts 192.168.29.172:/etc/hosts root192.168.29.172s password: bash: rsync: 未找到命令 rsync: connection unexpectedly closed (0 bytes receive…...

Selenium事件监听
引言 你一定总是渴望从WebDriver中获得更多的日志信息,以便调试你的脚本或记录更多有关测试的信息。这里为你提供了解决方案:EventFiringWebDriver 和 WebDriverEventListener。EventFiringWebDriver 是一个类,用于包装你的WebDriver以抛出事件,而WebDriverEventListener是…...

视频写作入门:9个步骤开始您的视频日志并与观众建立真实的联系
视频博客(vlogging)通过视频内容帮助你独特的声音和故事被听到,这能与你的观众建立强烈而有意义的联系,从而促进你的业务发展。使用光年AI平台,你可以将业务场景无缝接入AI能力,轻松实现私域流量的增长。 …...

使用豆包MarsCode 编写 Node.js 全栈应用开发实践
以下是「豆包MarsCode 体验官」优秀文章,作者狼叔。 欢迎更多用户使用豆包MarsCode 并分享您的产品使用心得及反馈、创意项目开发等,【有奖征集|人人都是豆包MarsCode 测评官!】活动正在火热进行中,欢迎大家投稿参加&a…...

Spring Cloud全解析:熔断之Hystrix执行流程
Hystrix执行流程 每次调用创建一个新的HystrixCommand,把依赖调用封装在run()方法中执行execute()/queue做同步或异步调用判断熔断器(circuit-breaker)是否打开,如果打开则执行fallback进行降级策略,如果关闭继续执行判断线程池/队列/信号量…...

大模型算法岗,面试百问百答,7天3个offer拿到手!
导读 大模型时代很多企业都在开发自己的大模型,这直接刺激了大模型岗位的需求。本文为大家整理了大模型面试相关的知识点,希望对大家面试求职有所帮助。 今天分享大模型面试相关知识点,持续更新。 1. RAG技术体系的总体思路 数据预处理->…...

代码随想录算法day32 | 动态规划算法part05 | 完全背包,518. 零钱兑换 II, 377. 组合总和 Ⅳ,70. 爬楼梯 (进阶)
完全背包理论基础 本题力扣上没有原题,大家可以去卡码网第52题 (opens new window)去练习,题意是一样的。 完全背包 有N件物品和一个最多能背重量为W的背包。第 i 件物品的重量是 weight[i],得到的价值是 value[i] 。每件物品都有无限个&…...

【Linux 从基础到进阶】自动化备份与恢复策略
自动化备份与恢复策略 在 Linux 运维中,数据的安全性至关重要,自动化备份与恢复策略是保障系统和数据安全的核心环节。无论是系统配置文件、用户数据、数据库还是应用程序日志,备份和恢复都能为系统灾难恢复、数据丢失等突发情况提供可靠的解决方案。 本文将介绍如何在 Ce…...

前端打包装包——设置镜像
1、打包失败,因为没装包,装包失败,因为装包的源错误 npm config get registry npm config set registry https://registry.npmmirror.com/npm install npm run build还是失败,因为缺少了包,在package.json文件中没有包…...

volatile 的作用?是否具有原子性,对编译器有什么影响?什么情况下一定要用 volatile, 能否和 const 一起使用?
目录 1. volatile 的作用 2. 是否具有原子性 3. 对编译器的影响 4.volatile 的使用场景 5.volatile 和 const 的组合 1. volatile 的作用 防止编译器优化:volatile 告诉编译器,变量的值可能会在程序的其他地方(如硬件中断、其他线程等&…...

iPhone 16分辨率,屏幕尺寸,PPI 详细数据对比 iPhone 16 Plus、iPhone 16 Pro、iPhone 16 Pro Max
史上最全iPhone 机型分辨率,屏幕尺寸,PPI详细数据!已更新到iPhone 16系列! 点击放大查看高清图 !...

FunASR搭建语音识别服务和VAD检测
搭建ASR语音识别服务(含VAD检测)教程 在本文中,我将为大家详细介绍如何搭建一套基于FunASR的ASR(语音识别)服务,并集成VAD(语音活动检测)。该服务使用阿里达摩院的模型,…...

设计一个支持多线程写入的并发日志记录系统:C++实战指南
设计一个支持多线程写入的并发日志记录系统:C实战指南 在现代软件开发中,日志记录是一个至关重要的功能,它帮助开发者调试、监控和维护系统。然而,在多线程环境中,日志记录系统需要处理多个线程同时写入日志的问题&am…...

使用LSTM(长短期记忆网络)模型预测股票价格的实例分析
一:LSTM与RNN的区别 LSTM(Long Short-Term Memory)是一种特殊的循环神经网络(RNN)架构。LSTM是为了解决传统RNN在处理长序列数据时遇到的梯度消失或梯度爆炸问题而设计的。 在传统的RNN中,信息通过隐藏状…...

开源的 Windows 12 网页体验版!精美的 UI 设计、丰富流畅的动画
大家周二好呀!博主今天给小伙伴们分享一款炫酷的 Windows 12 体验版,网页效果拉满,非常值得我们去尝试! 如果你对未来的Windows操作系统充满期待,那么这款开源的Windows 12 网页体验版绝对不容错过!这不仅…...

chapter14-集合——(List)——day18
目录 518-Set接口方法 518-Set接口方法...

Frida 脚本抓取 HttpURLConnection 请求和响应
引入 Java 类: 引入 okhttp3.OkHttpClient、okhttp3.OkHttpClient$Builder、okhttp3.Interceptor、okhttp3.ResponseBody 等类。 创建自定义拦截器: 通过 Java.registerClass 创建自定义拦截器 MyInterceptor。拦截器中重写 intercept 方法࿰…...

Java实现建造者模式和源码中的应用
Java实现建造者模式(Builder Pattern) 文章目录 Java实现建造者模式(Builder Pattern)案例:汉堡制作建造者模式的核心角色代码实现:汉堡制作 🍔内部类实现:Step 1:产品类…...

Windows安装docker
Windows有两种虚拟号技术,WLS和Hyper-V,因为我的win10是家庭版,所以只能采用WLS来安装docker。 在Windows 10家庭版中,由于默认不包含Hyper-V功能,因此容器功能也不可用。即使启用了Hyper-V,由于Docker De…...

SprinBoot+Vue校园车辆管理系统的设计与实现
目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍:CSDN认证博客专家,CSDN平台Java领域优质…...

【C语言进阶】C语言动态内存管理:深入理解malloc、calloc与realloc
📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C语言 “ 登神长阶 ” 🤡往期回顾🤡:C语言自定义类型 🌹🌹期待您的关注 🌹🌹 ❀C语言动态内存管理 &#…...

Java+控制台 图书管理系统
Java控制台 图书管理系统 一、系统介绍二、功能展示1.用户登陆2.普通用户:图书查询、图书借阅、图书归还 、图书列表3.管理员:图书整理、图书添加、图书删除 四、其它1.其他系统实现 一、系统介绍 系统实现了普通用户:图书查询、图书借阅、图书归还 、图…...