网络基础(2)
目录
- 1. 端口号
- 2. 套接字socket
- 3. 网络通信
- 3.1 sockaddr与sockaddr_in
- 3.2 接口
- 服务端
- 3.2.1 创建套接字,打开网络文件
- 3.2.2 给该服务器绑定端口和ip(特殊处理)
- 3.2.3 初始化相关服务器
- 3.2.4 提供服务
- 客户端
- 3.2.5 绑定
- 3.2.6 使用服务
- 4. makefile实现:
- 5. 整体代码
1. 端口号
IP能够唯一地标识互联网中的一台主机;而端口号能够唯一地标识一台机器上的唯一一个进程。
那么这两个因素加起来,就构成了能够标识互联网上的唯一一个进程。这就是端口号与IP的联系。
2. 套接字socket
整个网络看作是一个大的OS,所有网络上网行为,都是在这里面实现进程间通信的。
IP地址+port端口号 = socket
端口号之于进程PID,就相当于身份证号之于学生学号。
- 为什么有了PID,在网络里还需要端口号来进行标识?
这就好比学校不用身份证来对学生信息进行管理、录入。因为学校内部会有更合适的管理系统,采用自己一套的管理方式能够使管理更加得心应手,也不惧怕外部环境的改变,实现与外部解耦。PID和端口号也是这个原理。
3. 网络通信
3.1 sockaddr与sockaddr_in
要实现网络通信,首先是要找到目标主机,其次是找到该主机上的目标进程。
而进程具有独立性,要实现网络通信需要让两个进程看到同一份资源,这份资源就是网络。
应用层的下一层就是传输层,传输层有TCP/UDP协议。
- 统一接口
对于将要介绍的sock接口,要先说明一个概念,就是sockarr结构:由于各种网络协议的实现方式不同,导致接口需要对应设计,所以干脆就设计出来了一个通用的接口,该参数统一为sockaddr。
socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及UNIX DomainSocket。 然而, 各种网络协议的地址格式并不相同。
目前我们采用的是struct sockaddr,这是一个通用接口,也即是说,可以兼容后两个接口类型的参数。
通用接口与其他两个不同协议的接口:
虽然socket api的接口是sockaddr, 但是我们真正在基于IPv4编程时, 使用的数据结构是sockaddr_in; 这个结构里主要有三部分信息: 地址类型, 端口号, IP地址。
sockaddr与sockaddr_in其实都是结构体类型:
- sockaddr
它把目标地址和端口信息实现在一起:
struct sockaddr{sa_family_t sin_family;//16位地址类型家族char sa_data[14];//14位长度地址数据,包含套接字中的目标地址和端口信息
}
- sockaddr_in
sockaddr_in的头文件包含在:
#include <netinet/in.h>
#include <arpa/inet.h>
该结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中,如下
typedef uint16_t in_port_t;//十六位数字struct sockaddr_in{sa_family_t sin_family;//16位地址类型家族in_port_t sin_port;//16位端口号struct in_addr sin_addr;//32位ip地址unsigned char sin_zero;//未使用
}
in_addr其实就是32位的IPv4地址:
typedef uint32_t in_addr_t;struct in_addr{In_addr_t s_addr; //32位IPv4地址
};
- sockaddr_un
struct sockaddr_un{//16位地址类型//108字节路径名
}
IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6. 这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容。
socket API可以都用struct sockaddr * 类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数。
3.2 接口
服务端
3.2.1 创建套接字,打开网络文件
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
- 参数:
domain就是用来区分传入的是哪个协议种类。
type代表协议特性,是套接字类型。比如流式套结、原始套结等。
proyocol在tcp中只需要全部设置为0。
- 返回值:创建成功后,新的套接字会返回一个文件描述符。
#include <iostream>
#include <cerrno>
int main()
{int sock = socket(AF_INET,SOCK_DGRAM,0);if(sock < 0){std::cout<<"socket create error!"<<errno<<std::endl;return 1;}std::cout<<"sock:"<<sock<<std::endl;return 0;
}
运行结果:
3.2.2 给该服务器绑定端口和ip(特殊处理)
作为一个服务器,对应的服务器地址(IP+port)是必须要被客户(人、软件、浏览器)所知晓的,并且不能轻易地被改变。
- 首先要绑定端口号
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int sockfd, const struct sockaddr *addr,
socklen_t address_len);
- 参数
sockfd代表创建好的套接字的文件描述符;addr代表需要用户指定服务器的相关socket信息,address_len代表传入的结构体大小。
- 返回值
绑定成功返回0,失败返回-1,也可以是错误码。
3.2.3 初始化相关服务器
这里的参数addr是相关服务器的信息,所以要bind,就要先初始化好addr的信息:
首先定义一个sockaddr_in类型的结构体,因为我们平时传的addr其实是sockaddr_in类型的,只需要在绑定的时候做一下强转即可。
那么接下来就是将它里面的对应字段全部初始化:
const uint16_t port = 8080;
struct sockaddr_in local;
local.sin_family = AF_INET; //IPV4
local.sin_port = htons(port); //该端口号是主机序列,要改成网络序列
local.sin_addr.s_addr = INADDR_ANY;
其中port是主机序列,需要转为网络序列,使用的是htons函数:
h是host代表主机,n代表network网络:
剩下最后一个字段初始化为INADDR_ANY的意思是:由该服务器发送的,到任意主机(IP)上的数据都能被你的网络进程接收。
如果不这样初始化,而是绑定了确定的IP,例如:
//inet_addr函数将地址从数点法转化为整数IP
//网络需要的是整数表示IP而不是数点法表示的地址
local.sin_addr.s_addr = inet_addr("xx.xxx.xx.xxx");
这样的话,只有发送到该IP的数据才能被你进程接收,所以一般不这么写。
并且云服务器不直接绑定公网IP。
然后就可以进行绑定:
if(bind(sock,(struct sockaddr*)&lockal,sizeof(local)) < 0){std::cout << "bind error : " << errno << std::endl;return 2;
}
3.2.4 提供服务
绑定完成以后,等待他人给自己的服务器发送信息,是接收的过程。
- recvfrom
udp的数据读取不是用文件的接口,而是有专门的接口recvfrom:
参数:分别是自身套接字fd、读完的数据放到buf、读len大小、读的方式flag(默认0),剩下最后两个代表的是和你的服务器通信的客户端的信息,是一个输出型参数,作用是如需要返回数据给它,就可以拿到其地址返回。
- sendto
给对端发信息,用的是sendto
其他参数都一样,最后两个参数代表的是要给谁发:
由此可以提供服务:
// 3. 提供服务
#define NUM 1024
char buffer[NUM];
bool quit = false;
while(!quit){struct sockaddr_in send;socklen_t len = sizeof(send);//开始读recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&send,&len);std::cout << "client" << buffer << std::endl;//收到以后回复hellostd::string echo = "hello";sendto(sock,echo.c_str(),echo.size(),0,(struct sockaddr*)&send,len);}
客户端
3.2.5 绑定
客户端不需要显示绑定。
对于客户端来说,也必须要有套接字,但是它不需要显示绑定。因为一旦绑定了,它就要和某一个端口关联了,该端口不一定会存在,或者被占用,那么该客户端将无法使用。
对于服务端来说,端口必须要明确,并且不能变更;而对于客户端,只要有端口就行,因为是客户端访问他人。所以客户端一般都是由OS在发送数据的时候自动绑定,采用的是随机端口。
// 1. 创建
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd < 0){std::cout<<"socket create error!"<<errno<<std::endl;return 1;
}
std::cout<<"sock:"<<sockfd<<std::endl;
3.2.6 使用服务
实现基本和服务端一样,但是由于自定义遵守./udp_client server_ip server_port的格式,所以要用到命令行参数来规范行为,不规范的话会打印使用手册。
void Usage(std::string proc)
{std::cout << "Usage: \n\t"<< proc << " server_ip server_port" << std::endl;
}
int main(int argc,char* argv[])
{if(argc != 3){Usage(argv[0]);return 0;}// 1. 创建int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){std::cout<<"socket create error!"<<errno<<std::endl;return 1;}std::cout<<"client:sock:"<<sockfd<<std::endl;//客户端也必须要有套接字//不需要显示bind// 2. 使用服务// ./udp_client server_ip server_port的格式struct sockaddr_in server;server.sin_family = AF_INET;server.sin_port = htons(atoi(argv[2]));server.sin_addr.s_addr = inet_addr(argv[1]);while(1){// 1. 数据来源 std::string s;std::cout<<"输入# ";std::cin>>s;// 2. 发给谁sendto(sockfd,s.c_str(),s.size(),0,(struct sockaddr*)&server,sizeof(server));//此处tmp就是一个”占位符“struct sockaddr_in tmp;socklen_t len = sizeof(tmp);char buffer[1024];recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&tmp, &len);std::cout << "server echo# " << buffer << std::endl;}return 0;
}
由于云服务器需要手动在后台开通窗口才可通信,所以IP使用127.0.0.1来测试
下列运行结果:
客户端:
服务端:
4. makefile实现:
.PHONY:all
all:udp_server udp_clientudp_server:udp_server.ccg++ -o $@ $^ -std=c++11udp_client:udp_client.ccg++ -o $@ $^ -std=c++11.PHONY:clean
clean:rm -f udp_server udp_client
5. 整体代码
服务端:
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <cerrno>const uint16_t port = 8080;
int main()
{// 1. 创建套接字,打开网络文件int sock = socket(AF_INET,SOCK_DGRAM,0);if(sock < 0){std::cout<<"socket create error!"<<errno<<std::endl;return 1;}std::cout<<"server:sock:"<<sock<<std::endl;// 2. 给该服务器绑定端口和ipstruct sockaddr_in local;local.sin_family = AF_INET; //IPV4local.sin_port = htons(port); //该端口号是主机序列,要改成网络序列local.sin_addr.s_addr = INADDR_ANY;if(bind(sock,(struct sockaddr*)&local,sizeof(local)) < 0){std::cout << "bind error : " << errno << std::endl;return 2;}// 3. 提供服务#define NUM 1024char buffer[NUM];bool quit = false;while(!quit){struct sockaddr_in send;socklen_t len = sizeof(send);recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&send,&len);std::cout << "client say# " << buffer << std::endl;//收到以后回复hellostd::string echo = "hello";sendto(sock,echo.c_str(),echo.size(),0,(struct sockaddr*)&send,len);}return 0;
}
客户端:
#include <iostream>
#include <string>
#include <cerrno>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>//正确用法
// ./udp_client server_ip server_port的格式
void Usage(std::string proc)
{std::cout << "Usage: \n\t"<< proc << " server_ip server_port" << std::endl;
}
int main(int argc,char* argv[])
{if(argc != 3){Usage(argv[0]);return 0;}// 1. 创建int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){std::cout<<"socket create error!"<<errno<<std::endl;return 1;}std::cout<<"client:sock:"<<sockfd<<std::endl;//客户端也必须要有套接字//不需要显示bind// 2. 使用服务// ./udp_client server_ip server_port的格式struct sockaddr_in server;server.sin_family = AF_INET;server.sin_port = htons(atoi(argv[2]));server.sin_addr.s_addr = inet_addr(argv[1]);while(1){// 1. 数据来源 std::string s;std::cout<<"输入# ";std::cin>>s;// 2. 发给谁sendto(sockfd,s.c_str(),s.size(),0,(struct sockaddr*)&server,sizeof(server));//此处tmp就是一个”占位符“struct sockaddr_in tmp;socklen_t len = sizeof(tmp);char buffer[1024];recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&tmp, &len);std::cout << "server echo# " << buffer << std::endl;}return 0;
}
相关文章:
网络基础(2)
目录1. 端口号2. 套接字socket3. 网络通信3.1 sockaddr与sockaddr_in3.2 接口服务端3.2.1 创建套接字,打开网络文件3.2.2 给该服务器绑定端口和ip(特殊处理)3.2.3 初始化相关服务器3.2.4 提供服务客户端3.2.5 绑定3.2.6 使用服务4. makefile实…...
掌握Spring Cloud Gateway:构建高性能API网关的原理和实践
Spring Cloud Gateway 是一个基于 Spring Boot 的 API 网关,用于构建微服务架构中的网关服务。它提供了统一的路由、请求转发、过滤器、负载均衡、熔断等功能,帮助开发者更好地管理和控制微服务系统的请求流量。 本文将介绍 Spring Cloud Gateway 的原理…...
NAST概述
一、NATS介绍 NATS是由CloudFoundry的架构师Derek开发的一个开源的、轻量级、高性能的,支持发布、订阅机制的分布式消息队列系统。它的核心基于EventMachine开发,代码量不多,可以下载下来慢慢研究。 不同于Java社区的kafka,nats…...
【JS知识点】——原型和原型链
文章目录原型和原型链构造函数原型显式原型(prototype)隐式原型(\_\_proto\_\_)原型链总结原型和原型链 在js中,原型和原型链是一个非常重要的知识点,只有理解原型和原型链,才能深刻理解JS。在…...
c盘怎么清理到最干净?有什么好的清理方法
c盘怎么清理到最干净?有什么好的清理方法?清理C盘空间是电脑维护的重要步骤之一。C盘是Windows操作系统的核心部分,保存了许多重要的系统文件,因此空间不足会影响计算机的性能和稳定性。下面是一些清理C盘空间的方法 一.清理临时文件 在使用…...
day26_HTML
今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、二阶段介绍 二、HTML 零、 复习昨日 见代码 一、二阶段介绍 第一阶段: 基础入门 java基本语法编程基础(方法,数组)面向对象编程常用类高级(IO,线程,新…...
深度剖析C语言预处理
致前行的人: 人生像攀登一座山,而找寻出路,却是一种学习的过程,我们应当在这过程中,学习稳定冷静,学习如何从慌乱中找到生机。 目录 1.程序翻译过程: 2.字符串宏常量 3.用宏定义充当注释符号 4…...
【WPF 值转换器】ValueConverter 进阶用法
【WPF 值转换器】ValueConverter 进阶用法介绍基类实现子类实现效果介绍 值转换器在WPF开发中是非常常见的,当然不仅仅是在WPF开发中。值转换器可以帮助我们很轻松地实现,界面数据展示的问题,如:模块隐藏显示、编码数据展示为可读…...
Vue2的基本使用
一、vue的基本使用 第一步 引入vue.js文件 <script src"https://cdn.staticfile.org/vue/2.7.0/vue.min.js"></script> 或者<script src"./js/vue.js"></script> 第二步 在body中设置一个挂载点 {{msg}} <div id"app…...
【云原生kubernetes】k8s数据存储之Volume使用详解
目录 一、什么是Volume 二、k8s中的Volume 三、k8s中常见的Volume类型 四、Volume 之 EmptyDir 4.1 EmptyDir 特点 4.2 EmptyDir 实现文件共享 4.2.1 关于busybox 4.3 操作步骤 4.3.1 创建配置模板文件yaml 4.3.2 创建Pod 4.3.3 访问nginx使其产生访问日志 4.3.4 …...
SerDes---CDR技术
1、为什么需要CDR 时钟数据恢复主要完成两个工作,一个是时钟恢复,一个是数据重定时,也就是数据的恢复。时钟恢复主要是从接收到的 NRZ(非归零码)码中将嵌入在数据中的时钟信息提取出来。 2、CDR种类 PLL-Based CDROve…...
如何实现在on ethernetPacket中自动回复NDP response消息
对于IPv4协议来说,如果主机想通过目标ipv4地址发送以太网数据帧给目的主机,需要在数据链路层填充目的mac地址。根据目标ipv4地址查找目标mac地址,这是ARP协议的工作原理 对于IPv6协议来说,根据目标ipv6地址查找目标mac地址,它使用的不是ARP协议,而是邻居发现NDP(Neighb…...
CSS清楚浮动
先看看关于浮动的一些性质 浮动使元素脱离文档流 浮动元素可以设置宽高,在CSS中,任何元素都可以浮动,浮动元素会生成一个块级框,而不论其本身是何种元素。 如果没有给浮动元素指定高度,,那么它会以内容的…...
HTTPS详解(原理、中间人攻击、CA流程)
摘要我们访问浏览器也经常可以看到https开头的网址,那么什么是https,什么是ca证书,认证流程怎样?这里一一介绍。原理https就是httpssl,即用http协议传输数据,数据用ssl/tls协议加密解密。具体流程如下图&am…...
EventLoop机制
JavaScript 是单线程的语言 JavaScript 是一门单线程执行的编程语言。也就是说,同一时间只能做一件事情。 单线程执行任务队列的问题: 如果前一个任务非常耗时,则后续的任务就不得不一直等待,从而导致程序假死的问题。 同步任…...
倒立摆建模
前言 系统由一辆具有动力的小车和安装在小车上的倒立摆组成,系统是不稳定,我们需要通过控制移动小车使得倒立摆保持平衡。 具体地,考虑二维情形如下图,控制力为水平力FFF,输出为角度θ\thetaθ以及小车的位置xxx。 力…...
SpringSecurity支持WebAuthn认证
WebAuthn是无密码身份验证技术,解决了密码泄露的风险,主流的浏览器都支持。有很多开源的类库实现了WebAuthn规范,Java下流行的类库有:webauthn4jjava-webauthn-serververtx-authSpring Security官方暂时未支持WebAuthn,…...
深度学习技巧应用3-神经网络中的超参数搜索
大家好,我是微学AI,今天给大家带来深度学习技巧应用3-神经网络中的超参数搜索。 在深度学习任务中,一个算法模型的性能往往受到很多超参数的影响。超参数是指在模型训练之前需要我们手动设定的参数,例如:学习率、正则…...
【信号量机制及应用】
水善利万物而不争,处众人之所恶,故几于道💦 目录 一、信号量机制 二、信号量的应用 >利用信号量实现进程互斥 >利用信号量实现前驱关系 >利用记录型信号量实现同步 三、例题 四、参考 一、信号量机制 信号量是操作系统提…...
围棋高手郭广昌的“假眼”棋局
(图片来源于网络,侵删)文丨熔财经作者|易不二2022年,在复星深陷债务压顶和变卖资产漩涡的而立之年,“消失”已久的郭广昌,在质疑与非议声中回国稳定军心,强调复星将在未来的五到十年迎来一个全新…...
学成教育-统一异常处理实现
一、统一异常处理实现 统一在base基础工程实现统一异常处理,各模块依赖了base基础工程都 可以使用。 首先在base基础工程添加需要依赖的包: <dependency><groupId>org.springframework</groupId><artifactId>spring-web</…...
JNI内通过参数形式从C/C++中传递string类型数据至Java层
目录 0 前言 1 string类型参数形式传值 2 测试和结果 0 前言 类似之前我写过的两篇文章:一篇介绍了在JNI中基础类型int的传值方式;一篇详细梳理了在JNI层中多维数组的多种传值方式。 JNI内两种方式从C/C中传递一维、二维、三维数组数据至Java层详细…...
自动化测试——执行javaScript脚本
文章目录一、点击元素(对应的click())二、input标签对应的值(对应的send_keys())修改时间控件的属性值:三、元素的文本属性四、js脚本滚动操作一、点击元素(对应的click()) 使用场景:当使用显性等待不能解决问题时 代码中实现点击…...
常用十种算法滤波
十种算法滤波1. 限幅滤波法(又称程序判断滤波法)2. 中位值滤波法3. 算术平均滤波法4. 递推平均滤波法(又称滑动平均滤波法)5. 中位值平均滤波法(又称防脉冲干扰平均滤波法)6. 限幅平均滤波法7. 一阶滞后滤波…...
IO多路复用
一、概述 IO多路复用:进程同时检查多个文件描述符,以找出他们中的任何一个是否可执行IO操作。 核心:同时检查多个文件描述符,看他们是否准备好了执行IO操作。文件描述符就绪状态的转化是通过一些IO事件来触发。 二、水平触发和…...
Python中的错误是什么,Python中有哪些错误
7.1 错误(errors) 由于Python代码通常是人类编写的,那么无论代码是在解释之前还是运行之后,或多或少总会出现一些问题。 在Python代码解释时遇到的问题称为错误,通常是语法和缩进问题导致的,这些错误会导致代码无法通过解释器的解…...
记录自己开发一款小程序中所遇到的问题(uniapp+uview)(持续更新)
每次开发小程序中,都会遇到各种各样的问题。但是有的问题已经遇到过了,但是遇到的时候还是要各种的问度娘。 特此出这篇文章,方便自己也是方便大家。 仅供参考 1. u-collapse的样式在h5中正常,但是运行到微信小程序中样式就乱了…...
华为机试 HJ43 迷宫问题
经典迷宫问题dfs 题目链接 描述 定义一个二维数组 N*M ,如 5 5 数组下所示: int maze[5][5] { 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, }; 它表示一个迷宫,其中的1表示墙壁,0表示可以走…...
数据结构|链表
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。单链表的形式就像一条铁链环环相扣它与顺序表最大的不同是,单链表的数据存储是在不连续的空间,存储的数据里面含有…...
计算机写论文时,怎么引用文献? - 易智编译EaseEditing
首先需要清楚哪些引用必须注明[1]: 任何直接引用都要用引号并注明来源; 任何不是自己的口头或书面的观点、解释和结论都应注明来源; 即使不用原话,但是他人的思路、概念或观点也应注明; 不要为了适合你的观点修改原…...
如何在年报网站上做遗失公告/今日最新国内新闻重大事件
合理维护网络服务器安全的七个小技巧对于一个网络而言,维护其服务器安全的重要性是不言而喻的,那么作为管理员的你如何来更好地保障服务器的安全呢?本文较系统地给您介绍一些实用的技巧。 技巧一:从基本做起 ***开始对你的网络发起***的时候&…...
海尔网站建设水平/一键seo提交收录
方案(模式)是一个属于某个用户的所有对象的统称。 当你建立表空间、用户,并且建立了对象(如表、存储过程...)后,你就有了方案。 也就是这些对象的统称。 我曾经测试过oracle自带的hr方案,用system/manage连接,呵呵,当…...
网站上的二维码怎么做/网站百度收录秒收方法
APP性能测试工具——GT 使用方法 场景介绍 通过GT工具兼容移动端的 CPU、内存、流量、电量、帧率/流畅度等等GT官方使用介绍文档地址:https://gt.qq.com一、工具下载 应用宝下载GT app并安装 二、工具介绍 1.打开GT,允许访问权限 进入工具AUT页面&…...
珠海哪家做企业网站公司好/咖啡seo是什么意思
航空订票系统系统(SSHMYSQLHTML5)(毕业论文近10000字, 包含程序代码,MySql数据库,数据库脚本) 【项目包含】【项目功能】【源码下载】本系统登录的角色有二种:会员、管理员、普通用户。管理员是能够管理会员信息、航班信息的管理、订单信息的管理、留言板的管理。会…...
厦门网站关键词优化/保定seo推广公司
什么是spring Spring是java企业级应用的开源开发框架。Spring主要用来开发java应用,但是有些扩展是针对于J2EE平台的web应用。其目的是为了简化java企业级应用开发。 使用Spring框架的好处是什么 轻量:基本的版本大约为2MB控制反转Ioc:spr…...
wordpress 客户端使用/百度ai营销中国行
38-博客网站数据库-博文分类信息数据操作(二) 项目描述 当今网上微博、博客发布信息已经成为主要的信息发布、传播的系统,如何对这些数据进行管理,本项目主要是对博客网站中的博文分类信息表、博文信息表进行操作。 博客网站的数据库操作要求如下&…...