领航Linux UDP:构建高效网络新纪元

欢迎来到 破晓的历程的 博客

⛺️不负时光,不负己✈️

文章目录

    • 引言
    • Udp和Tcp的异同
      • 相同点
      • 不同点
      • 总结
    • 1.1、socket
    • 1.2、bind
    • 1.3、recvfrom
    • 1.4、sendto
    • 2.1、代码
    • 2.1、说明
    • 3.1、代码
    • 3.2、说明

引言

在前几篇博客中,我们学习了Linux网络编程中的一些概念。从本篇博客开始,我们就正式开始写代码。本篇博客我们将写udp服务器和客户端代码,并实现服务器和客户端通信。这些代码学习成本较高,建议大家多敲几遍。如任何问题,欢迎与我沟通。

Udp和Tcp的异同

UDP协议(User Datagram Protocol,用户数据报协议)和TCP协议(Transmission Control Protocol,传输控制协议)是计算机网络中两种常用的传输层协议,它们在多个方面存在显著的异同。以下是对两者异同点的详细比较:

相同点

  • 层次位置:两者都位于OSI模型的第四层——传输层,为上层应用提供数据传输服务。
  • 作用:都在网络通信中扮演着重要的角色,用于在网络中的不同设备之间传输数据。

不同点

UDP协议TCP协议
可靠性不提供可靠性保证,不保证数据包的顺序、完整性和不重复。提供可靠的数据传输,通过序列号、确认机制和重传机制确保数据的完整性和有序性。
连接性无连接协议,发送数据前不需要建立连接,直接发送数据。面向连接的协议,数据传输前需要建立连接,通过“三次握手”机制确认连接状态。
传输效率传输效率高,因为不需要建立连接和维持连接状态,开销小。传输效率相对较低,因为需要建立和维护连接,增加了额外的开销。
实时性实时性较好,适用于对实时性要求较高的应用,如在线游戏、视频通话等。实时性较差,因为需要等待连接建立和确认,以及处理重传等机制。
数据包大小数据包大小没有限制,但通常受限于网络MTU(最大传输单元)。将数据分割成较小的数据块进行传输,以适应不同的网络环境。
拥塞控制不使用拥塞控制,网络拥塞时不会降低发送速率。使用拥塞控制机制,根据网络状况调整发送速率,避免网络拥塞。
应用场景适用于对可靠性要求不高,但对实时性要求较高的场景,如流媒体传输、DNS查询等。适用于对可靠性要求较高的场景,如文件传输、网页浏览等。

总结

UDP协议和TCP协议在可靠性、连接性、传输效率、实时性、数据包大小和拥塞控制等方面存在显著的差异。选择哪种协议取决于具体的应用场景和需求。如果对数据传输的可靠性要求较高,应选择TCP协议;如果对实时性要求较高,且可以容忍一定的数据丢失,则可以选择UDP协议。在实际应用中,两种协议经常结合使用,以满足不同的网络需求。

不难发现,Udp代码较简单,写起来相对的简单一些,上手较容易。所以我们写使用Udp协议进行通信。

为了使大家更加容易理解。我们按照创建udp服务端的整个过程的先后顺序来进行讲解。最后写出完整的代码。

1.1、socket

网络通信必须要申请套接字。申请套接字对应的函数为socket。

       #include <sys/types.h>          /* See NOTES */#include <sys/socket.h>int socket(int domain, int type, int protocol);

参数
①domain
在这里插入图片描述
domain(协议域/协议族):决定了socket的地址类型。常用的协议族有AF_INET(IPv4)、AF_INET6(IPv6)、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等。在通信中,必须采用与协议族对应的地址。例如,AF_INET决定了要使用IPv4地址(32位)与端口号(16位)的组合。

②type

在这里插入图片描述
type(socket类型):指定了socket的类型。常用的socket类型有SOCK_STREAM(流式套接字,用于TCP)、SOCK_DGRAM(数据报套接字,用于UDP)、SOCK_RAW(原始套接字,允许对底层协议如IP或ICMP进行直接访问)等。
③protocol
protocol(协议):通常情况下,可以将其设置为0,让系统自动选择type类型对应的默认协议。
返回值

  • 当socket函数成功创建了一个套接字时,它返回一个有效的套接字描述符(socket descriptor)。这个描述符是一个非负整数,用于后续的网络操作,如绑定、监听、连接、发送和接收数据等。
  • 如果在创建套接字时发生错误,socket函数返回-1,并设置全局变量errno以指示错误原因。此时,可以调用errno变量或perror()函数来获取具体的错误信息。常见的错误码包括EACCES(权限不足)、EADDRINUSE(地址已经被占用)、EAFNOSUPPORT(地址族不支持)、EINVAL(参数无效)、EMFILE(达到进程允许打开的最大文件数目)、ENFILE(系统打开文件数目过多)、ENOBUFS/ENOMEM(内存不足)、EPROTONOSUPPORT(协议不支持)等。

1.2、bind

bind函数在网络编程中扮演着至关重要的角色,它主要用于将一个本地协议地址(包括IP地址和端口号)赋予一个套接字。以下是关于bind函数的详细解释:

       #include <sys/types.h>          /* See NOTES */#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

参数
①sockfd:这是由socket()函数返回的文件描述符,代表已经创建的套接字。
②addr:这是一个指向特定协议地址结构的指针,如struct sockaddr_in或struct sockaddr_un,它包含了地址、端口和可能的IP地址信息。
③addrlen:这是地址结构的长度,通常以字节为单位。对于IPv4,通常使用sizeof(struct sockaddr_in);对于IPv6,使用sizeof(struct sockaddr_in6);对于Unix域套接字,使用sizeof(struct sockaddr_un)。
返回值:

  • 如果bind函数成功执行,它返回0。
  • 如果出现错误,返回-1,并设置全局变量errno以指示错误原因。常见的错误包括EACCES(权限不足)、EADDRINUSE(地址已经被使用)、EADDRNOTAVAIL(地址不可用)、EAFNOSUPPORT(地址族不支持该套接字类型)、EINVAL(套接字未打开)、ENOTSOCK(文件描述符不是套接字)等。

使用场景:

在TCP服务器程序中,bind函数通常用于指定服务器应监听的端口号。服务器在启动时捆绑其众所周知的端口,以便客户端可以连接到它。
对于UDP套接字,bind函数同样用于指定接收数据的端口号。
在Unix域套接字中,bind函数可以用来指定套接字在文件系统中的路径名。

注意事项:

  • 在调用bind函数之前,套接字必须处于未连接状态(对于面向连接的套接字如TCP)。
  • 如果addr参数中的地址或端口号为0,系统将为套接字自动选择一个可用的地址或端口号。
  • 在多线程环境中,应确保对bind函数的调用是线程安全的,避免竞态条件。
  • 绑定的本质:将用户态的sockaddr_in设置进内核变为系统态。
  • 对于端口号而言,如果用户没有调用bind函数进行显式绑定,那么系统在第一次发送消息时,会随机给套接字绑定一个端口号。

1.3、recvfrom

recvfrom函数是一个在POSIX兼容操作系统(如Linux)中用于接收数据的系统调用。它主要用于从指定的套接字接收数据,并适用于面向无连接的协议,如UDP(用户数据报协议)。

       #include <sys/types.h>#include <sys/socket.h>ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

参数
①sockfd:已经创建并绑定的套接字的文件描述符。
②buf:创建好的一块缓冲区的地址。用来承接从网络中读取到的数据。
③len:该块缓冲区的大小。
④flags:读取数据的方式。默认设为0——阻塞式读取。
⑤src_addr输出型参数,该结构体里面包含着数据发送方的信息,如port、ip等等。如果不需要这些信息,可以设为null。
⑥‘’addrlen:该结构体的大小。

返回值

  • 成功时,返回接收到的字符数(字节数)。
  • 如果没有可用数据或者连接已经关闭,返回0。
  • 如果出现错误,返回-1,并设置errno错误号。此时可以通过perror()函数来打印出错误信息。

注意事项

  • 在调用recvfrom函数之前,需要先使用bind函数将socket绑定到一个地址上。
  • 如果套接字是非阻塞的,recvfrom函数可能会在没有接收到任何数据时返回-1,并设置errno为EAGAIN或EWOULDBLOCK。
  • 如果接收到的数据比缓冲区还大,那么只会取缓冲区大小的数据,并将剩余的数据丢弃。

1.4、sendto

sendto函数是一个系统调用,用于将数据从指定的套接字发送到目标地址。它通常用于UDP(用户数据报协议)通信,因为UDP是无连接的,所以sendto函数允许你向一个特定的地址发送数据报,而不需要事先建立连接。

#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

参数

  • sockfd:已经创建好的socket文件描述符。
  • buf:指向要发送的数据的缓冲区。
  • len:要发送的数据长度。
  • flags:发送选项标志,可以是0或者像MSG_DONTWAIT这样的选项。MSG_DONTWAIT表示非阻塞发送,如果发送缓冲区满,则不等待直接返回。
  • dest_addr:目标地址的sockaddr结构体指针。对于IPv4,这通常是一个指向struct sockaddr_in的指针;对于IPv6,则是一个指向struct sockaddr_in6的指针。
  • addrlen:目标地址结构体的长度,例如sizeof(struct sockaddr_in)或sizeof(struct sockaddr_in6)。

返回值:

sendto函数的返回值是一个long类型的整数,表示发送的字节数。具体返回值有以下几种可能:

  • 如果返回值大于0,则表示数据已经成功发送到了目标地址。返回值代表实际发送的字节数。
  • 如果返回值等于0,表示发送的数据长度为0。这可能是因为buf指向的空间长度为0,或者在使用UDP协议时,sendto函数成功地发送了0字节的数据。
  • 如果返回值等于-1,表示发送过程中出现了错误。此时,可以通过检查errno的值来确定具体的错误原因。例如,如果errno为EINTR,表示sendto函数被一个信号中断了;如果errno为EAGAIN或EWOULDBLOCK,表示发送缓冲区已满,无法立即发送数据(这通常发生在使用了MSG_DONTWAIT标志的情况下)。

需要注意的是,sendto函数不保证数据的可靠传输。也就是说,发送的数据可能会丢失,或者接收方可能无法按照发送的顺序接收数据。如果需要可靠的数据传输,应该使用TCP协议而不是UDP。
此外,在使用sendto函数之前,需要确保已经通过socket函数创建了一个套接字,并且(对于面向连接的套接字类型)已经通过connect函数与目标地址建立了连接(尽管对于UDP,连接通常不是必需的,但也可以通过connect建立默认的目标地址)。同时,也需要确保目标地址是有效的,并且发送的数据缓冲区是正确设置的。

udp服务端

2.1、代码

#pragma once#include <iostream>
#include <string>
#include <strings.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>namespace Server
{using namespace std;static const string defaultIp = "0.0.0.0"; //TODOstatic const int gnum = 1024;enum {USAGE_ERR = 1, SOCKET_ERR, BIND_ERR};typedef function<void (string,uint16_t,string)> func_t;class udpServer{public:udpServer(const func_t &cb, const uint16_t &port, const string &ip = defaultIp):_callback(cb), _port(port), _ip(ip), _sockfd(-1){}void initServer(){// 1. 创建socket_sockfd = socket(AF_INET, SOCK_DGRAM, 0);if(_sockfd == -1){cerr << "socket error: " << errno << " : " << strerror(errno) << endl;exit(SOCKET_ERR);}cout << "socket success: " << " : " << _sockfd << endl;// 2. 绑定port,ip(TODO)// 未来服务器要明确的port,不能随意改变struct sockaddr_in local; // 定义了一个变量,栈,用户bzero(&local, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port); // 你如果要给别人发消息,你的port和ip要不要发送给对方local.sin_addr.s_addr = inet_addr(_ip.c_str());   // 1. string->uint32_t 2. htonl(); -> inet_addr//local.sin_addr.s_addr = htonl(INADDR_ANY); // 任意地址bind,服务器的真实写法int n = bind(_sockfd, (struct sockaddr*)&local, sizeof(local));if(n == -1){cerr << "bind error: " << errno << " : " << strerror(errno) << endl;exit(BIND_ERR);}// UDP Server 的预备工作完成}void start(){// 服务器的本质其实就是一个死循环char buffer[gnum];for(;;){// 读取数据struct sockaddr_in peer;socklen_t len = sizeof(peer); //必填ssize_t s = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&peer, &len);// 1. 数据是什么 2. 谁发的?if(s > 0){buffer[s] = 0;string clientip = inet_ntoa(peer.sin_addr); //1. 网络序列 2. int->点分十进制IPuint16_t clientport = ntohs(peer.sin_port);string message = buffer;cout << clientip <<"[" << clientport << "]# " << message << endl;// 我们只把数据读上来就完了吗?对数据做处理_callback(clientip, clientport, message);}}}~udpServer(){}private:uint16_t _port;string _ip; // 实际上,一款网络服务器,不建议指明一个IPint _sockfd;func_t _callback; //回调};
}

2.1、说明

  • 服务器一旦开始运行,就不会停止。所以服务器本质就是一个死循环。这种一直运行的进程叫做常驻进程。
  • 一般来说,服务器不会显式的绑定某一个ip。因为一个主机可能会有不同的ip。但是这台主机内的端口号是唯一的,客户端都是发送信息到特定的端口号上。所以服务器为了可以接收到所有发到这台主机上的信息(不会存在数据丢弃的情况),选择绑定0.0.0.0作为自己的ip。这样就可以接受到任何发送到这台主机指定端口的所有信息。

udp客户端

3.1、代码

#include <iostream>
#include <string>
#include <strings.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>namespace Client
{using namespace std;class udpClient{public:udpClient(const string &serverip, const uint16_t &serverport): _serverip(serverip), _serverport(serverport), _sockfd(-1), _quit(false){}void initClient(){// 创建socket_sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd == -1){cerr << "socket error: " << errno << " : " << strerror(errno) << endl;exit(2);}cout << "socket success: "<< " : " << _sockfd << endl;// 2. client要不要bind[必须要的],client要不要显示的bind,需不需程序员自己bind?不需要!!!// 写服务器的是一家公司,写client是无数家公司 -- 由OS自动形成端口进行bind!-- OS在什么时候,如何bind}static void *readMessage(void *args){int sockfd = *(static_cast<int *>(args));pthread_detach(pthread_self());while (true){char buffer[1024];struct sockaddr_in temp;socklen_t temp_len = sizeof(temp);size_t n = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&temp, &temp_len);if (n >= 0)buffer[n] = 0;cout << buffer << endl;}return nullptr;}void run(){pthread_create(&_reader, nullptr, readMessage, (void *)&_sockfd);struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_addr.s_addr = inet_addr(_serverip.c_str());server.sin_port = htons(_serverport);string message;char cmdline[1024];while (!_quit){//cerr << "# "; // ls -a -l// cin >> message;fprintf(stderr, "Enter# ");fflush(stderr);fgets(cmdline, sizeof(cmdline), stdin);cmdline[strlen(cmdline)-1] = 0;message = cmdline;sendto(_sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&server, sizeof(server));}}~udpClient(){}private:int _sockfd;string _serverip;uint16_t _serverport;bool _quit;pthread_t _reader;};
} // namespace Client

3.2、说明

客户端需要绑定端口号吗?客户端需要显式的绑定端口号吗?

端口号是需要绑定端口号的,但是不需要显式的绑定端口号的。绑定端口号的工作交给操作系统自主完成,这个工作由操作系统在客户端初次发送消息时完成。

相对于服务端来说,客户端必须绑定特定的端口号,但是端口号的数值对于客户端来说就显得不太重要。

服务端必须指定特定的端口号以供客户端根据该端口号来向服务端发送消息。但是客户端而言,如果显式指明端口号,必然会出现两个客户端竞争一个端口号的情况。所以在通信时就由操作系统随机分配一个端口号供客户端进行通信。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/46930.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构(邓俊辉)学习笔记】高级搜索树02——B树

文章目录 1. 大数据1.1 640 KB1.2 越来越大的数据1.3 越来越小的内存1.4 一秒与一天1.5 分级I/O1.6 1B 1KB 2. 结构2.1 观察体验2.2 多路平衡2.3 还是I/O2.4 深度统一2.5 阶次含义2.6 紧凑表示2.7 BTNode2.8 BTree 3. 查找3.1 算法过程3.2 操作实例3.3 算法实现3.4 主次成本3.…

JAVASE——图书管理系统

JAVASE图书管理系统 主要业务有&#xff1a;管理员(增删改查)&#xff0c;会员&#xff08;借书还书查看记录&#xff09; 管理员主要有&#xff1a;查看图书&#xff0c;增加图书&#xff0c;修改图书&#xff0c;会员管理&#xff0c;删除图书&#xff0c; 会员主要有&#x…

昇思25天学习打卡营第22天|GAN图像生成

今天是参加昇思25天学习打卡营的第22天&#xff0c;今天打卡的课程是“GAN图像生成”&#xff0c;这里做一个简单的分享。 1.简介 今天来学习“GAN图像生成”&#xff0c;这是一个基础的生成式模型。 生成式对抗网络(Generative Adversarial Networks&#xff0c;GAN)是一种…

Bug:时间字段显示有问题

Bug&#xff1a;时间字段显示有问题 文章目录 Bug&#xff1a;时间字段显示有问题1、问题2、解决方法一&#xff1a;添加注解3、解决方法二&#xff1a;消息转换器自定义对象映射器配置消息转换器 1、问题 ​ 在后端传输时间给前端的时候&#xff0c;发现前端的时间显示有问题…

[Spring] Spring Web MVC案例实战

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

AV1技术学习:Translational Motion Compensation

编码块根据运动矢量在参考帧中找到相应的预测块&#xff0c;如下图所示&#xff0c;当前块的左上角的位置为(x0, y0)&#xff0c;在参考帧中找到同样位置(x0, y0)的块&#xff0c;根据运动矢量移动到目标参考块&#xff08;左上角位置为&#xff1a;(x1, y1)&#xff09;。 AV1…

前端a-tree遇到的问题

在使用a-tree时候&#xff0c;给虚拟滚动的高度&#xff0c;然后展开a-tree滑动一段距离 比如这样 随后你切换页面&#xff0c;在返回这个页面的时候 就会出现这样的bug 解决方法&#xff1a; onBeforeRouteLeave((to, from, next) > {// 可以在路由参数变化时执行的逻辑ke…

白山云荣获信通院“算网安全行业应用优秀案例”奖

日前&#xff0c;在由中国通信标准化协会算网融合产业及标准推进委员会与信通院共同组织召开的“2024年算网融合产业发展大会”上&#xff0c;白山云凭借创新的SD-WAN算网融合方案&#xff0c;荣获“算网安全行业应用优秀案例”奖。 算网融合是多元异构、海量泛在的算力设施&am…

path模块和HTTP协议

一。path模块常用API ./相对路径&#xff0c;/绝对路径 二&#xff0c;HTTP协议 1.请求报文 1.请求行 URL的组成 2.请求头 3.请求体 可以是空&#xff1a;GET请求 可以是字符串&#xff0c;还可以是json&#xff1a;POST请求 2.响应报文 1.响应行 HTTP / 1.1 200 OK H…

VsCode 与远程服务器 ssh免密登录

首先配置信息 加入下列信息 Host qb-zn HostName 8.1xxx.2xx.3xx User root ForwardAgent yes Port 22 IdentityFile ~/.ssh/id_rsa 找到自己的公钥&#xff0c;不带pub是私钥&#xff0c;打死都不能给别人。复制公钥 拿到公钥后&#xff0c;来到远程服务器 vim ~/.ss…

Leetcode—3011. 判断一个数组是否可以变为有序【中等】(__builtin_popcount()、ranges::is_sorted())

2024每日刷题&#xff08;144&#xff09; Leetcode—3011. 判断一个数组是否可以变为有序 O(n)复杂度实现代码 class Solution { public:bool canSortArray(vector<int>& nums) {// 二进制数位下1数目相同的元素就不进行组内排序// 只进行分组// 当前组的值若小于…

人工智能算法工程师(中级)课程12-PyTorch神经网络之LSTM和GRU网络与代码详解1

大家好,我是微学AI,今天给大家介绍一下人工智能算法工程师(中级)课程12-PyTorch神经网络之LSTM和GRU网络与代码详解。在深度学习领域,循环神经网络(RNN)因其处理序列数据的能力而备受关注。然而,传统的RNN存在梯度消失和梯度爆炸的问题,这使得它在长序列任务中的表现不尽…

MySQL--C_C++语言连接访问

Connector/C的使用 首先需要在mysql官网下载C接口库 解压指令 tar -zxvf 压缩包名 下载并解压好后 但是还有比这更优的做法。 这样子手动安装不仅麻烦&#xff0c;还可能存在兼容性的问题。 其实在我们使用yum安装mysql时&#xff0c;大概率会自动帮我们把其他的环境都安装…

【Datawhale AI夏令营】电力需求预测挑战赛 Task01

整个学习活动&#xff0c;将带你从 跑通最简的Baseline&#xff0c;到了解竞赛通用流程、深入各个竞赛环节&#xff0c;精读Baseline与进阶实践 文章目录 一、赛题背景二、赛题任务三、实践步骤学习规划分析思路常见时序场景 task01codecode 解读 一、赛题背景 随着全球经济的…

CSA笔记1-基础知识和目录管理命令

[litonglocalhost ~]$ 是终端提示符&#xff0c;类似于Windows下的cmd的命令行 litong 当前系统登录的用户名 分隔符 localhost 当前机器名称&#xff0c;本地主机 ~ 当前用户的家目录 $ 表示当前用户为普通用户若为#则表示当前用户为超级管理员 su root 切换root权限…

昇思25天学习打卡营第12天|munger85

基于MindSpore通过GPT实现情感分类 这个实现情感分类意思就是通过一些电影的数据最后知道他对于这个电影的评价&#xff0c;最后知道他对于这个电影的评价到底是好还是不好&#xff0c;零就是不好&#xff0c;一就是好。首先我们肯定是按安装这些依赖包了为了今天这个模型我们…

【Apache Doris】周FAQ集锦:第 14 期

【Apache Doris】周FAQ集锦&#xff1a;第 14 期 SQL问题数据操作问题运维常见问题其它问题关于社区 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目&#xff01; 在这个栏目中&#xff0c;每周将筛选社区反馈的热门问题和话题&#xff0c;重点回答并进行深入探讨。旨在为广大用户…

深度加速器 为游戏而生

使用深度加速器的基本步骤如下 首先&#xff0c;访问深度加速器的官方网站或授权下载渠道&#xff0c;下载最新版本的深度加速器客户端。 下载完成后&#xff0c;电脑版直接双击打开免安装&#xff0c;将深度加速器安装到您的计算机或移动设备上。 注册与登录&#xff1a; 打…

如何构建全生命周期的安全体系架构来确保容器的安全?

容器技术在云原生应用和微服务架构中得到了广泛应用&#xff0c;其轻量、灵活和高效的特点使其成为现代IT环境中的重要工具。然而&#xff0c;尽管容器带来了许多优势&#xff0c;但其安全性问题也不容忽视。接下来跟随博主一起探索如何构建全生命周期的安全体系架构以确保容器…

Vue3 子组件像父组件传递数据 自定义事件 defineEmits

介绍 很多情况下子组件都需要像父组件去传递一些数据&#xff0c;Vue3和Vue2传递值的写法不太一样。 例子 很常见的一个案例&#xff0c;弹出一个商品对话框&#xff0c;用户选择商品后把商品信息返回给父组件&#xff0c;使用自定义事件去做。 子组件 选择商品对话框 &…