socket网络编程
端口 :主机上一个应用程序的代号(端口不变)
为什么不用PID来表示一个应用
因为PID会变化,而端口是不变的
套接字进程间通信——跨越主机
1、主机字节序列和网络字节序列
主机字节序列分为大端字节序和小端字节序,不同的主机采用的字节序列可能不同。大
端字节序是指一个整数的高位字节存储在内存的低地址处,低位字节存储在内存的高地址
处。小端字节序则是指整数的高位字节存储在内存的高地址处,而低位字节则存储在内存的
低地址处。 在两台使用不同字节序的主机之间传递数据时,可能会出现冲突。所以,在将数
据发送到网络时规定整形数据使用大端字节序,所以也把大端字节序成为网络字节序列。对
方接收到数据后,可以根据自己的字节序进行转换
Linux 系统提供如下 4 个函数来完成主机字节序和网络字节序之间的转换:
# include <netinet/in.h> uint32_t htonl(uint32_t hostlong);//长整型的主机字节转网络字节序 uint32_t ntohl(uint32_t netlong);//长整型的网络字节序转主机字节序 uint32_t htons(uint16_t hostshort);//短整型的主机字节转网络字节序列 uint32_t ntonhs(uint16_t hostshort);//短整型的网络字节序列转主机字节序列
2.套接字地址结构
2.1通用socket地址结构
socket网络编程接口中表示socket地址是结构体sockaddr,其定义如下:
# include <bits/socket.h> struct sockaddr//通用套接字地址结构 {sa_family_t sa_family;char sa_data[14]; }
sa_family成员是地址族类型(sa_family_t)的变量。地址族类型通常与协议族类型对应。常见的协议族和对应的地址族如下图所示:
2.2 专用socket地址结构
TCP/IP协议族有sockaddr_in和sockaddr_in6两个专用socket地址结构体,它们分别用于IPV4和IPV6:
/*sin_family:地址族 AF_INETsin_port:端口号,需要用网络字节序表示sin_addr:IPV4地址结构:s_addr以网络字节序表示IPV4地址 */ struct in_addr {u_int32_t s_addr; }; struct sockaddr_in {sa_family sin_family;u_int16_t sin_port;struct in_addr sin_addr; }; struct in6_addr {unsigned char sa_addr[16]; }; struct sockaddr_in6 {sa_family_t sin6_family;//地址族:AF_INETu_inet16_t sin6_port;//端口号:用网络字节序表示u_int32_t sin6_flowinfo;//流信息,应设置为0struct in6_addr sin6_addr;//IPV6地址结构体u_int32_t sin6_scope_id;//scope ID,尚处于实验阶段 };
2.3 IP地址转换函数
通常,人们习惯用点分十进制字符串表示IPV4地址,但编程中我们需要把它们转换成整数方能使用,下面函数可用于点分十进制字符串表示的IPV4地址和网络字节序整数表示的IPV4地址之间的转换:
# include <arpa/inet.h> in_addr_t inet_addr(const char*cp);//字符串表示的IPV地址转化为网络字节序 char*inet_ntoa(struct in_addr in);//IPV4地址的网络字节序转化为字符串表示
3.网络编程接口
# include <sys.types.h> # include <sys/socket.h> int socket(int domain,int type,int protocol); /* socket()创建套接字,成功返回套接字的文件描述符,失败返回-1 第一个参数:domain(地址族):AF_UNIX、AF_INET、AF_INET6 第二个参数:type(服务类型):设置套接字的服务类型SOCK_STREAM(TCP协议) SOCK_DGRAM(UDP协议) 第三个参数:protocol(协议版本):一般设置为0,表示使用默认协议 */ int bind(int sockfd,const struct sockaddr*addr,socklen_t addrlen); /* bind():将sockfd与一个socket地址绑定,成功返回0,失败返回-1 sockfd是网络套接字描述符 addr是地址结构 addrlen是socket地址长度 */ int listen(int sockfd,int backlog); /* listen()创建一个监听队列以存储待处理的客户连接,成功返回0,失败返回-1 sockfd是被监听的socket套接字 backlog表示处于完全连接状态的socket的上限 */ int accept(int sockfd,struct sockaddr*addr,socklen_t*addrlen); /* accept()从listen监听队列中接收一个连接,成功返回一个新的连接socket,该socket唯一地标识了被接收的这个连接,失败返回-1 sockfd是执行过listen系统调用的监听socket addr参数用来获取被接受连接的远端socket地址 addrlen指定该socket地址的长度 */ ssize_t recv(int sockfd,void*buff,size_t len,int flags); ssize_t send(int sockfd,const void*buff,size_t len,int flags); /* TCP数据读写: recv()读取sockfd上的数据,buff和len参数分别指定读缓冲区的位置和大小 send()往socket上写入数据,buff和len参数分别指定写缓冲区的位置和数据长度 flgs参数为数据收发提供了额外的控制 */ int connect(int sockfd,const struct sockaddr*serv_addr,socklen_t addrlen); /* connect()客户端需要通过此系统调用来主动与服务器建立连接,成功返回0,失败返回-1 第一个参数:sockfd时由socket()返回的一个套接字标识符 第二个参数:serv_addr是服务器监听的socket地址 第三个参数:addrlen则指定这个地址的长度 */ ssize_t recvfrom(int sockfd,void*buff,size_t len,int flags,struct sockaddr*src_addr,socklen_t*addrlen); ssize_t sendto(int sockfd,void*buff,size_t len,int flags,struct sockaddr*dest_addr,socklen_t addrlen); /* UDP数据读取: recvfrom()读取sockfd上的数据,buff和len参数分别指读缓冲区的位置和大小,src_addr记录发生端的socket地址,addrlen指定该地址的长度 sendto()往socket上写入数据,buff和冷参数分别指读取缓冲区的位置和数据长度,dest_addr指定接收数据端的地址,addrlen指定该地址的长度 */
4.TCP编程流程
TCP提供的是面向连接的、可靠的、字节流服务。TCP的服务器端和客户端编程流程如下:
socket()方法是用来创建一个套接字,有了套接字就可以通过网络进行数据的收发。这也是为什么进行网络通信的程序首先要创建一个套接字。创建套接字时要指定使用的服务类型,使用TCP协议选择流式服务(SOCK_STREAM)。
bind()方法是用来指定套接字使用的IP地址和端口。IP地址就是自己主机的地址,如果主机没有接入网络,测试程序时可以使用回环地址"127.0.0.1"。端口是一个16位的整形值,一般0-1024为知名端口,入HTTP使用的是80号端口。这类端口一般用户不能随便使用。其次,1024-4096为保留端口,,用户一般也不用。4096以上为临时端口,用户可以使用。在Linux上,1024以内的端口只有root用户可以使用。
listen()方法是用来创建监听队列。监听队列有两种,一个是存放未完成三次握手的连接,一种是存放已完成三次握手的连接。listen()第二个参数就是指定已完成三次握手队列的长度。
accept()处理存放在listen创建的已完成三次握手的队列中的连接。每处理一个连接,则accept()返回该连接对应的套接字描述符。如果该队列为空,则accept()阻塞。
connect()方法一般由客户端程序执行,需要指定连接的服务器端的IP地址和端口。该方法执行后,会进行三次握手,建立连接。
send()方法用来向TCP连接的对端发送数据。send()执行成功,只能说明将数据成功写入到发送端的发送缓冲区中,并不能说明数据已经发送到了对端。send()的返回值为实际写入到发送端缓冲区中的数据长度。
recv()方法用来接收TCP连接的对端发送来的数据。recv()从本端的缓冲区中读取数据,如果接收缓冲区中没有数据,则recv()方法会阻塞。返回值是实际读到的字节数,如果recv()返回值为0,说明对方已经关闭了TCP连接。
close()方法用来关闭TCP连接。此时,会进行四次挥手。
TCP服务端代码ser.c如下:
# include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <assert.h> # include <sys/socket.h> # include <arpa/inet.h> # include <netinet/in.h> int main () {int sockfd=socket(AF_INET,SOCK_STREAM,0);//第一步创建套接字assert(sockfd!=-1);struct sockaddr_in saddr;//IPV4地址结构,saddr以网络字节序列表示地址结构memset(&saddr,0,sizeof (saddr));//清空saddr,防止占用空间saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);//htons将主机字节序转换为网络字节序saddr.sin_addr.s_addr=inet_addr("127.0.0.1");//回环地址int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//讲套接字标识符与套接字socket地址绑定,成功返回0,失败返回-1.assert(res!=-1);res=listen(sockfd,5);//创建一个监听队列,处理待处理的连接assert(res!=-1);while(1){struct sockaddr_in caddr;//远端连接服务器的地址结构socklen_t len=sizeof (caddr);int c=accept(sockfd,(struct sockaddr*)&caddr,&len);//从listen监听队列中接收一个连接,成功返回一个新的连接socket,该socket唯一地标识了被接收的这个连接,失败返回-1if (c==-1){continue;}printf("accept c=%d\n",c);char data[128]={0};int n=recv(c,data,127,0);printf ("n=%d,buff=%s\n",n,data);send(c,"ok",2,0);close(c);//关闭连接,开始四次挥手 } close(sockfd); exit(0); }
TCP客服端代码cli.c如下:
# include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <assert.h> # include <sys/socket.h> # include <arpa/inet.h> # include <netinet/in.h> int main () {int sockfd=socket(AF_INET,SOCK_STREAM,0);assert(sockfd!=-1);struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof (saddr));//客服端需要通过此系统调用来主动与服务器端建立连接,成功返回0,失败返回-1。assert(res!=-1);printf ("please input:");char buff[128]={0};fgets(buff,128,stdin);send(sockfd,buff,strlen(buff)-1,0);//往socked上写入数据int n=recv(sockfd,data,127,0);//读取sockfd上的数据printf ("%s\n",data);close(sockfd);exit(0); }
结果:
5.多进程、多线程处理并发
如图所示,当一个客户端与服务器建立连接以后·,服务器端accept()返回,进而准备循环接收客服端发过来数据 。如果客服端暂时没发数据,服务端会在recv()阻塞。此时其他客户端向服务器发起连接后,由于服务器阻塞了,无法执行accept()接受连接,也就是其他客户端发生的数据,服务器无法读取,服务器也就无法并发同时处理多个客户端。
这个问题可以通过引入多线程或多进程来解决。服务器端接受一个客服端的连接后,创建一个线程或者进程,然后在新创建的线程中循环处理数据。主线程(父进程)只负责监听客服端的连接,并使用accept()接受连接,不进行数据的处理。如下图所示:
多线程处理并发的服务器端代码ser.c如下:
# include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <string.h> # include <assert.h> # include <sys/socket.h> # include <netinet/in.h> # include <arpa/inet.h> # include <pthread.h> void*fun(void *arg) {int c=(int)arg;while (1){char buff[128]={0};if (recv(c,buff,127,0)<=0){break;}printf ("recv(%d)=%s\n",c,buff);send(c,"ok",2,0);}printf ("one client over(%d)\n",c);close(c); } int main () {int sockfd=socket(AF_INET,SOCK_STREAT,0);assert(sockfd!=-1);struct sockaddr_in saddr,caddr;memset(&saddr,0,sizeof (saddr));saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));assert(res!=-1);res=listen(sockfd,5);assert(res!=-1);while (1){int len=sizeof(caddr);int c=accept(sockfd,(struct sockaddr*)&caddr,sizeof (caddr));if (c<0){continue;}printf ("accept c=%d\n",c);pthread_t id;pthread_create(&id,NULL,fun,(void*)c);}close(sockfd);exit(0); }
6.UDP编程流程
UDP提供的是无连接、不可靠、数据服务。编程流程如下。
socket()用来创建套接字,使用udp协议时,选择数据报服务SOCK_DGRAM。sendto()用来发送数据,由于udp时无连接的,每次发送数据都需要指定对端的地址(IP和端口)。recvfrom()接收数据,每次都需要传给该方法一个地址结构来存放发送端的地址·。recvfrom()可以用来接收所有客服端发送给当前应用程序的地址,并不是一个只能接收某一个客服端的数据。
UDP服务端编程代码示例:
# include <stdio.h> # include <stdlib.h> # include <string.h> # include <unistd.h> # include <assert.h> # include <sys/socket.h> # include <netinet/in.h> # include <arpa/inet.h> int main () {int sockfd=socket(AF_INET,SOCK_DGRAM,0);assert(sockfd!=-1);struct socksaddr_in saddr,caddr;memset(&saddr,0,sizeof (saddr));saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");int res=bind(sockfd,(struct saddr*)&saddr,sizeof(saddr));assert(res!=-1);while (1){int len=sizeof(caddr);char buff[128]={0};recvfrom(sockfd,buff,127,0,(struct sockaddr*)&caddr,&len);printf ("ip:%s,port:%d,buff=%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),buff);sendto(sockfd,"ok",2,0,(struct sockaddr*)&caddr,sizeof (caddr));}close(sockfd); }
UDP客户端代码:
# include <stdio.h> # include <stdlib.h> # include <string.h> # include <unistd.h> # include <sys/socket.h> # include <assert.h> # include <netinet/in.h> # include <arpa/inet.h> int main () {int sockfd=socket(AF_INET,SOCK_DGRAM,0);assert(sockfd!=-1);struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family=AF_INET;saddr.sin_port=htons(6000);saddr.sin_addr.s_addr=inet_addr("127.0.0.1");while(1){char buff[128]={0};printf ("input:\n");fgets(buff,128,stdin);if(strcnmp(buff,"end",3)==0){break;}sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&saddr,sizeof(saddr));memset(buff,0,128);int len=sizeof(saddr);recvfrom(sockfd,buff,127,0,(struct saddr*)&saddr,&len);printf ("buff=%s\n",buff);} close(sockfd); }
相关文章:

socket网络编程
端口 :主机上一个应用程序的代号(端口不变) 为什么不用PID来表示一个应用 因为PID会变化,而端口是不变的 套接字进程间通信——跨越主机 1、主机字节序列和网络字节序列 主机字节序列分为大端字节序和小端字节序,不同…...

IO多路复用机制详解
高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型。 (2)同步非阻塞IO(Non-blo…...

选择一款好用的营销项目管理可以更好帮您解决任何问题
营销项目管理软件哪个好用?使用Zoho Projects营销项目管理软件,您可以从营销活动中获得最佳结果,并获得可执行的见解。Zoho Projects的营销项目管理软件可让您和您的团队全面了解您的所有活动。监控您的社交渠道、跟踪结果并在一处进行交流。…...
计算机网络(第八版)第三章知识总结(期末复习可用)
本笔记来源于博主上课所记笔记整理,可能不全,欢迎大家批评指正,如果觉得有用记得点个赞,给博主点个关注...该笔记将会持续更新...整理不易,希望大家多多点赞。 第一章 第三章 数据链路层 数据链路层属于计算机网络的低…...

VScode配置8086汇编环境
目录 0、感慨 1、VScode的安装 2、下载MASM/TASM插件 3、测试汇编环境 新建文件 汇编文件配置 汇编代码的运行 0、感慨 搭配一个简单些的环境,对于我们汇编的学习很有帮助,在这里又不得不感叹vscode的强大,使用VScodeMASM/TASM插件就…...

银行数字化转型导师坚鹏:银行同业核心产品与营销策略解读
数字化背景下银行同业核心产品与营销策略解读课程背景: 数字化背景下,很多银行存在以下问题:不清楚银行同业核心产品发展现状?不清楚如何银行同业产品营销策略?不知道如何更好地挖掘他行优质客户? 课…...

在线答题考试小程序源码系统 支持在线刷题+考试二合一+安装部署教程
分享一个在线答题考试小程序源码系统,支持在线刷题考试二合一,程序包含前后端和详细的安装部署教程,可以用来给学生刷题,给员工刷题,给政企员工刷题,万能通用版适合任何行业在线刷题及考试。 系统功能一览&…...

同城跑腿小程序怎么做
随着市场需求越来越大,分工越来明细,很多人看到了跑腿类的商机,特别是学校、小区、商务园等场所。无论是校园跑腿还是社会类跑腿,例中代取快递、代拿包裹、代搬东西上下楼、代排队、帮忙办事、代买东西、代送等等功能都少不了&…...

爬虫逆向学习(五):使用RPC框架serkio解决逆向难题
serkio应用实战前言实战开发多次调用加密方法破解失败如何刷新加密方法同一个浏览器的加密代码如何给不同用户使用注意事项总结前言 最近在工作中遇到了一个反爬虫产品,处于技术能力和新产品迭代更新快的考虑,最后选择使用RPC技术解决问题,因…...

NumPy 秘籍中文第二版:三、掌握常用函数
原文:NumPy Cookbook - Second Edition 协议:CC BY-NC-SA 4.0 译者:飞龙 在本章中,我们将介绍许多常用函数: sqrt(),log(),arange(),astype()和sum()ceil(),modf()&…...

蓝桥杯基础17:BASIC-02试题 序列求和
资源限制 内存限制:256.0MB C/C时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s 问题描述 求123...n的值。 输入格式 输入包括一个整数n。 输出格式 输出一行,包括一个整数,表示123...n…...
vue移动端实现vue-pdf在线预览与展示,并且解决页面汉字空白的问题
vue移动端实现pdf的页面在线预览展示,CMapReaderFactory可以解决文字不展示、空白问题 //1、安装依赖vue-pdf npm install --save vue-pdf//2、使用组件 <pdf v-for"i in numPages" ref"pdfs" :src"pdfUrl" :key"i" …...
代码随想录算法训练营第四十九天 | 121. 买卖股票的最佳时机、122.买卖股票的最佳时机II
打卡第49天,买卖股票系列了 今日任务 ● 121. 买卖股票的最佳时机 ● 122.买卖股票的最佳时机II 121. 买卖股票的最佳时机 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#x…...
【职场篇】程序员是否吃青春饭?程序员在35岁之后是否需要转行?
你们好 那么众所周知呢像空姐 还有模特这种职业呢 都是吃青春饭的 那么到了一定年龄呢 他们可能就不做这一行了 那么其实程序员这个职业呢 有的人认为他也是吃青春饭的 普遍人都认为呢 如果程序员做到35岁呢 没有转管理岗位 可能以后就没有什么前途了 可能就要考虑换别的行业了…...

( “树” 之 DFS) 226. 翻转二叉树 ——【Leetcode每日一题】
226. 翻转二叉树 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 示例 1: 输入:root [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1] 示例 2: 输入:root [2,1,3] 输出:[…...

实验7---myBatis和Spring整合
实验七 myBatis和Spring整合 一、实验目的及任务 通过该实验,掌握mybatis和spring整合方法,掌握生成mapper实现类的两种生成方式。 二、实验环境及条件 主机操作系统为Win10,Tomcat,j2sdk1.6或以上版本。 三、实验实施步骤 略 四、实验报告内…...

DJ3-4 传输层(第四节课)
目录 一、TCP 概述 二、TCP 报文段的首部字段格式 三、TCP 往返时延的估计和超时 1. 估计往返时间 2. RTT 估计例子 3. 估计往返时间的偏差 4. 设置重传超时间隔 一、TCP 概述 全双工服务:允许在同一时间同一连接上,数据能够双向传输。注意&#…...

2023爱分析·商业智能应用解决方案市场厂商评估报告:数聚股份
目录 1. 研究范围定义 2. 商业智能应用解决方案市场分析 3. 厂商评估:数聚股份 4. 入选证书 1. 研究范围定义 商业智能(BI)是在实现数据集成和统一管理的基础上,利用数据存储和处理、分析与展示等技术,满足企…...
Kotlin方法执行顺序
方法的执行顺序 主构造函数init代码块次构造函数...

Ubuntu系统配置SonarQube + cppcheck + Jenkins
SonarQube1. postgresql安装及配置1.1 安装postgresql1.2 创建sonarqube用户1.3 设置数据库2. 安装sonarqube2.1 设置sonarqube2.2 修改sonarqube目录权限2.3 sonar.properties2.4 设置systemd管理sonarqube2.5 web3. 配置sonarscanner3.1 下载3.2 配置4. 配置cppcheck4.1 下载…...

JAVA反序列化应用 : URLDNS案例
反序列化的基本原理 基础普及 : 对象初始化数据方法 :1、使用构造方法 2、使用封装中的 set,get方法 这边我们就使用 1 注意 我们之后还需要进行 接入 序列化的接口 : 先进行序列化 : 反序列化: 反序列化导致的安…...

Vue-Leaflet地图组件开发(三)地图控件与高级样式设计
第三篇:Vue-Leaflet地图控件与高级样式设计 1. 专业级比例尺组件实现 1.1 比例尺控件集成 import { LControl } from "vue-leaflet/vue-leaflet";// 在模板中添加比例尺控件 <l-control-scaleposition"bottomleft":imperial"false&qu…...

Python数据可视化科技图表绘制系列教程(二)
目录 表格风格图 使用Seaborn函数绘图 设置图表风格 设置颜色主题 图表分面 绘图过程 使用绘图函数绘图 定义主题 分面1 分面2 【声明】:未经版权人书面许可,任何单位或个人不得以任何形式复制、发行、出租、改编、汇编、传播、展示或利用本博…...
MySQL从入门到DBA深度学习指南
目录 引言 MySQL基础入门 数据库基础概念 MySQL安装与配置 SQL语言进阶 数据库设计与规范化 数据库设计原则 表结构设计 MySQL核心管理 用户权限管理 备份与恢复 性能优化基础 高级管理与高可用 高可用与集群 故障诊断与监控 安全与审计 DBA实战与运维 性能调…...

Bootstrap Table开源的企业级数据表格集成
Bootstrap Table 是什么 Bootstrap Table 是一个基于 Bootstrap 框架的开源插件,专为快速构建功能丰富、响应式的数据表格而设计。 它支持排序、分页、搜索、导出等核心功能,并兼容多种 CSS 框架(如 Semantic UI、Material Design 等&am…...

分类场景数据集大全「包含数据标注+训练脚本」 (持续原地更新)
一、作者介绍:六年算法开发经验、AI 算法经理、阿里云专家博主。擅长:检测、分割、理解、大模型 等算法训练与推理部署任务。 二、数据集介绍: 质量高:高质量图片、高质量标注数据,吐血标注、整理,可以作为…...

EasyRTC嵌入式音视频通信SDK音视频功能驱动视频业务多场景应用
一、方案背景 随着互联网技术快速发展,视频应用成为主流内容消费方式。用户需求已从高清流畅升级为实时互动,EasyRTC作为高性能实时音视频框架,凭借低延迟、跨平台等特性,有效满足市场对多元化视频服务的需求。 二、EasyRTC技术…...

pgsql batch insert optimization (reWriteBatchedInserts )
reWriteBatchedInserts 是 PostgreSQL JDBC 驱动 提供的一个优化选项,它可以 重写批量插入语句,从而提高插入性能。 作用 当 reWriteBatchedInsertstrue 时,PostgreSQL JDBC 驱动会将 多个单独的 INSERT 语句 转换为 一个多行 INSERT 语句&a…...
MyBatis中foreach集合用法详解
在 MyBatis 中,<foreach> 标签用于遍历集合(Collection、List、Array、Map),常用于构建动态 SQL 语句(如 IN 查询、批量插入等)。以下是详细用法和示例: 核心属性 属性描述collection必填…...

【八股消消乐】构建微服务架构体系—服务注册与发现
😊你好,我是小航,一个正在变秃、变强的文艺倾年。 🔔本专栏《八股消消乐》旨在记录个人所背的八股文,包括Java/Go开发、Vue开发、系统架构、大模型开发、具身智能、机器学习、深度学习、力扣算法等相关知识点ÿ…...