【网络】套接字 -- UDP
🥁作者: 华丞臧.
📕专栏:【网络】
各位读者老爷如果觉得博主写的不错,请诸位多多支持(点赞+收藏+关注)。如果有错误的地方,欢迎在评论区指出。
推荐一款刷题网站 👉 LeetCode刷题网站
文章目录
- 一、网络编程套接字
- 1.1 认识端口号
- 1.2 认识UDP和TCP协议
- 1.3 网络字节序
- 二、UDP套接字
- 2.1 sockaddr结构
- 2.2 简单的UDP网络程序
- 2.1 socket 常见API
- recvform
- bind
- inet_addr
- 2.1 封装 UdpSocket
- server
- init
- start
- 2.2 udpclient
- 2.4 日志显示
- 2.5 测试
一、网络编程套接字
在数据包的头部中,有两个IP地址,分别叫做源IP地址和目的IP地址;但是光有这两个IP地址不能实现网路通信;在计算机上进行通信的时候,实际上是用户和用户在进行网络通信,而用户通常是用程序体现的,也就是说用户是通过计算机上的某一个进程(软件)来进行数据的交互。
结论:网络通信的本质就是进程间的通信。
因此在实现网络通信时,不仅需要IP地址来确保主机的唯一性,还需要一个标记来确保主机上进程的唯一性。我们将这个表示主机上进程唯一性的标记称为端口号。
1.1 认识端口号
端口号(port)是传输层协议的内容。
- 端口号是一个2字节16位的整数。
- 端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理。
- IP地址 + 端口号能够标识网络上的某一台主机的某一个进程。
- 一个端口号只能被一个进程占用。
- 端口号可以将操作系统的进程管理和网络解耦。
- 进程不一定都需要网络通信,端口号可以标识需要进行网络通信的进程。
- 0~1023的端口号是已经被使用了的,用户的端口号只能从1024 ~ 65536。
理解端口号和进程PID:
- PID表示唯一一个进程;
- 端口号也表示唯一一个进程;
- 一个进程可以绑定多个端口号;
- 一个端口号只能绑定唯一一个进程。
1.2 认识UDP和TCP协议
传输层协议(TCP和UDP)的数据段中有两个端口号,分别叫做源端口号和目的端口号,就是在描述 “数据是谁发的, 要发给谁”。
对TCP(Transmission Control Protocol 传输控制协议)有一个直观的认识,此处先了解TCP:
- 传输层协议
- 有连接
- 可靠传输
- 面向字节流
对UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识,此处先了解UDP:
- 传输层协议
- 无连接
- 不可靠传输
- 面向数据报
UDP实现足够简单,TCP实现较为复杂;两个协议各有优缺点,不同场景选择合适的协议即可。
1.3 网络字节序
内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分, 那么如何定义网络数据流的地址呢?
两台主机进行网络通信,发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址。
世界各地的计算机生产厂商非常多, 因此对于发送方和接收方的大小端字节序是无法确定的。无法控制通信双方主机,但是我们可以规定网络中的字节序;TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。不管这台主机是大端机还是小端机,都会按照这个TCP/IP规定的网络字节序来发送/接收数据;如果当前发送主机是小端,就需要先将数据转成大端;否则就忽略, 直接发送即可。
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络
字节序和主机字节序的转换。

- 这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。
- 例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。
- 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回。
- 如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。
二、UDP套接字
2.1 sockaddr结构
socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及后面要讲的UNIX Domain Socket。然而,各种网络协议的地址格式并不相同。用于本地通信和用于网络通信的套接字接口需要的数据都是不同的,为了能够使用统一的接口来实现网络通信和本地通信,接口设计者给出了一个 抽象结构,如下图:

系统中存在三种结构体,struct sockaddr(抽象类型)、struct sockaddr_in(INET网路套接字)、struct sockaddr_un(Unix域套接字套接字)。struct sockaddr内部会处理判断数据的前16位进行类型识别,然后强转成对应的类型实现切片,可以理解为C++的中多态。
-
IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型, 16位端口号和32位IP地址。
-
IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6。这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容。
-
socket API可以都用struct sockaddr *类型表示,在使用的时候需要强制转化成sockaddr_in;这样的好处是程序的通用性, 可以接收IPv4, IPv6,以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数。
sockaddr 结构

sockaddr_in 结构

虽然socket api的接口是sockaddr, 但是我们真正在基于IPv4编程时, 使用的数据结构是sockaddr_in;这个结构里主要有三部分信息: 地址类型, 端口号, IP地址。
in_addr结构

in_addr用来表示一个IPv4的IP地址. 其实就是一个32位的整数。
2.2 简单的UDP网络程序
2.1 socket 常见API
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);
说明:
-
domain:域,进行本地通信还是网络通信。
- AF_UNIX:本地通信;
- AF_INET:IPV4;
-
type:套接字类型,决定通信对应的报文类型,常用的为流式和用户数据报。
-
protocol:协议类型,网络应用中直接设为0即可。
-
socket套接字返回的是文件描述符,可以理解所有网络操作最终都是文件描述符级的操作。
recvform
用于从套接字文件描述符中读取数据。
#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:用于接收数据的指针,从sockfd文件中读取的数据放入指针指向的空间中;
- len:读取数据的字节数;
- flags:模式;
- src_addr:用于接收读取对方的port和ip地址;
- addrlen:src_addr数据的字节大小;
bind
用于绑定网络信息,指明ip和port。
#include <sys/types.h>
#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
- sockfd:套接字文件描述符;
- addr:需要绑定的sockaddr结构;
- addrlen:对应sockaddr结构的字节大小;
inet_addr
用于将字符串中的点分十进制转换成32位4字节的表示形式。
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>int inet_aton(const char *cp, struct in_addr *inp);in_addr_t inet_addr(const char *cp);in_addr_t inet_network(const char *cp);char *inet_ntoa(struct in_addr in);struct in_addr inet_makeaddr(int net, int host);in_addr_t inet_lnaof(struct in_addr in);in_addr_t inet_netof(struct in_addr in);
2.1 封装 UdpSocket
server
server是提供服务的一端,可以理解为服务器,用来接收用户传输的消息,同时也可以给用户发消息;可以将服务器封装成一个类,类当中包含套接字的初始化以及提供服务的接口,启动服务器时必须将端口号以参数的形式传递给main函数,ip地址可传可不传。
#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>#include "Log.hpp"static void Usage(const std::string porc)
{std::cout << "Usage:\n\t" << porc << " port [ip]" << std::endl;
}// 写一个简单的udpSever
// 云服务器有一些特殊情况:
// 1. 禁止你bind云服务器上的任何确定IP, 只能使用INADDR_ANY,如果你是虚拟机,随意class UdpServer
{
public:UdpServer(int port, std::string ip = ""):sockfd_(-1),port_(port),ip_(ip){}~UdpServer(){}
public:void init() //初识化server{} void start() //server开始服务{}
private:// 服务器的fdint sockfd_;// 服务器必须得有端口号信息uint16_t port_;// 服务器必须得有IP地址std::string ip_;
};// ./server port ip
int main(int argc, char *argv[])
{if(argc != 2 && argc != 3) {Usage(argv[0]);exit(PARA_ERR);}uint16_t port = atoi(argv[1]); std::string ip;if(argc == 3){ip = argv[2];}UdpServer server(port,ip);server.init(); // 创建并配置套接字server.start(); // 提供服务return 0;
}
init
初识化的任务主要是创建套接字,将套接字绑定网络信息指明ip和port。一般初识化分为以下几个步骤:

void init(){// 1. 创建套接字// domain -- 域// type -- 套接字类型,SOCK_DGRAM--数据报格式// protocol -- 协议类型,网络应用中:0// 返回值其实是文件描述符sockfd_ = socket(AF_INET, SOCK_DGRAM, 0); //就是打开一个文件if(sockfd_ < 0){logMessage(FATAL, "socket:%s:%d", strerror(errno), sockfd_);exit(SOCK_ERR);}logMessage(DEBUG, "socket create success:%d", sockfd_);// 2. 绑定网络信息,指明ip+port// 2.1 先填充基本信息到 struct sockaddr_instruct sockaddr_in local;bzero(&local, sizeof(local)); //初始化为0local.sin_family = AF_INET; //填充协议家族,域local.sin_port = htons(port_); //填充服务对应的端口号信息,一定会发给对方,因此port_一定回到网络中//local.sin_addr;local.sin_addr.s_addr = ip_.empty()? htonl(INADDR_ANY) : inet_addr(ip_.c_str()); // htonl将INADDR_ANY转换成32位网络字节序, inet_addr将字符串中的点分十进制转换成32位比特位if(bind(sockfd_, (const struct sockaddr*)&local, sizeof(local)) == -1){logMessage(FATAL, "bind:%s", strerror(errno));exit(BIND_ERR);}logMessage(DEBUG, "socket bind success:%d", sockfd_);//完成}
start
start()是server提供服务的接口,因此该函数必须是一个死循环(服务器都是在一个死循环当中)以给用户提供持续的服务;在start函数中,主要完成接收用户发送的消息并且将消息提取出来,其主要步骤如下图:

void start()
{// 服务器都是在一个死循环当中char inbuffer[1024]; //将来读取到的数据,都放在这里char outbuffer[1024]; //将来发送的数据,都放在这里while(true){struct sockaddr_in peer; //输出型参数socklen_t len = sizeof(peer); //输入输出型参数// UDP是无连接的// 对方发消息,你需要接收消息ssize_t s = recvfrom(sockfd_, inbuffer, sizeof(inbuffer) - 1, 0, \(struct sockaddr*)&peer, &len);logMessage(DEBUG, "server 提供服务中.....");if(s > 0) {//接收成功inbuffer[s] = '\0';}else if(s == -1){//logMessage(WARINING, "recvfrom fialed:%s[%d]", strerror(errno), sockfd_);continue;}// 读取成功的,除了读取到对方的数据,你还要读取到对方的网络地址[ip:port]std::string peerIp = inet_ntoa(peer.sin_addr); //拿到对方的ipuint32_t peerPort = ntohs(peer.sin_port); //拿到对方的port// 打印出来客户端给服务器发送过来的消息logMessage(NOTICE, "[%s:%d]# %s", peerIp.c_str(), peerPort, inbuffer);logMessage(DEBUG, "server 提供服务中.....");//sleep(1);}
}
2.2 udpclient
客户端用来连接服务器,并且使用服务器提供的服务;用户想要客户端与服务器进行网络通信就必须将服务器使用的端口号和ip传给客户端,客户端通过端口号和ip可以实现与服务器地网络通信。

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include "Log.hpp"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>static void Usage(std::string name)
{std::cout << "Usage:\n\t" << name << " server_ip server_port" << std::endl;
} // ./udpClient IP port
int main(int argc, char* argv[])
{if(argc != 3) //必须等于3,必须传ip和port{Usage(argv[0]);exit(PARA_ERR);}std::string ip = argv[1];uint16_t port = atoi(argv[2]);// 2. 创建客户端// 2.1 创建socketint sockfd = socket(AF_INET, SOCK_DGRAM, 0);assert(sockfd > 0);struct sockaddr_in ser;bzero(&ser, sizeof ser);ser.sin_family = AF_INET; //填充与服务器相同的协议ser.sin_port = htons(port); //服务器的端口号ser.sin_addr.s_addr = inet_addr(ip.c_str()); //服务器ipstd::string buffer;while(true){std::cerr << "Please Enter# ";std::getline(std::cin, buffer);// 发送消息给serversendto(sockfd, buffer.c_str(), buffer.size(), 0,(const struct sockaddr *)&ser, sizeof(ser)); // 首次调用sendto函数的时候,我们的client会自动bind自己的ip和port}close(sockfd);return 0;
}
2.4 日志显示

- vs_start:使用距离可变参数最近的一个参数初始化ap;
- va_arg:对可变参数列表提参,提参类型为type;
- va_end:将ap指针置为空;
//将可变参数列表全部转化为某个字符串当中
int vsnprintf(char *str, size_t size, const char *format, va_list ap);说明:str:用于保存数据的字符串数组地址;size:最大写入的空间大小;format:以什么格式化写入;ap:可变参数列表部分;
#pragma once
#include <cstdio>
#include <ctime>
#include <cstdarg>
#include <cassert>
#include <cstring>
#include <cerrno>
#include <stdlib.h>#define DEBUG 0
#define NOTICE 1
#define WARINING 2
#define FATAL 3
#define SOCK_ERR 4
#define BIND_ERR 5
#define PARA_ERR 6const char *log_level[]={"DEBUG", "NOTICE", "WARINING", "FATAL"};// logMessage(DEBUG, "%d", 10);
void logMessage(int level, const char *format, ...)
{assert(level >= DEBUG);assert(level <= FATAL);char *name = getenv("USER"); //获取用户名char logInfo[1024];va_list ap; // ap -> char* //va_start(ap, format); //vsnprintf(logInfo, sizeof(logInfo)-1, format, ap); //写入logInfova_end(ap); // ap = NULLFILE *out = (level == FATAL) ? stderr:stdout;fprintf(out, "%s | %u | %s | %s\n", \log_level[level], \(unsigned int)time(nullptr),\name == nullptr ? "unknow":name,\logInfo);
}
2.5 测试
- 使用127.0.0.1可以进行本地通信。

- 使用云服务器的ip地址可以进行网络通信。

相关文章:
【网络】套接字 -- UDP
🥁作者: 华丞臧. 📕专栏:【网络】 各位读者老爷如果觉得博主写的不错,请诸位多多支持(点赞收藏关注)。如果有错误的地方,欢迎在评论区指出。 推荐一款刷题网站 👉 LeetCode刷题网站 文章…...
Lambda原理及应用
Lambda原理及应用 Lambda介绍 Lambda 是 JDK8 以后版本推出的一个新特性,也是一个重要的版本更新,利用 Lambda 可以简化内部类,可以更方便的进行集合的运算,让你的代码看起来更加简洁,也能提升代码的运行效率。 Lambda语法 非…...
运动耳机推荐、最值得入手的运动耳机清单共享
现在市面上各式各样的运动蓝牙耳机着实让人挑花了眼,怎样才能从纷繁复杂的市场中挑选出专业性、安全性、舒适性等各个方面都做地可圈可点的运动蓝牙耳机可真不是一件易事啊,甚至连不少老朋友都会踩坑,为了能让大家挑到真正的运动蓝牙耳机,为此…...
c盘爆满--如何清理电脑C盘
问题 c盘饱满很多天了,今天终于忍无可忍,开始展开对c盘的处理 c盘的基本处理有两步, 第一步,电脑系统清理 1,c盘右键属性,有个磁盘清理,好像是系统更新的一些缓存资源,可以直接清理 当然这只…...
Nginx配置web服务器及部署反向代理
Nginx配置web服务器及部署反向代理配置web服务器location语法部署反向代理代理转发配置web服务器 项目部署到linux上的静态文件代理给Nginx处理。当访问服务器IP时,可以自动返回静态文件主页。 主配置文件中server块对应的次配置include /etc/nginx/conf.d/*.conf…...
mvvm和mvc
mvvm是model-view-viewmodel的缩写,前端开发的架构模式 m: model:模型,指的是数据和交互业务逻辑 v: view:视图,用户看到的ui界面 vm: viewmodel:视图模型࿰…...
JavaScript while 循环
JavaScript while 循环的目的是为了反复执行语句或代码块。只要指定条件为 true,循环就可以一直执行代码块。while 循环while 循环会在指定条件为真时循环执行代码块。语法while (条件){需要执行的代码 }实例本例中的循环将继续运行,只要变量 i 小于 5&a…...
CMU15-445 Project.0总结
在线测试 本地测试 Project #0 - C Primer 以下是Project #0的网址,2022FALL的Project #0本质上是实现一棵字典树,关于字典树的相关内容可以参考C实现字典树。 在本题中,为了存储对应着字符串的任意类型值,题目设计了一个Tri…...
计算机网络题库---错题本
(一)老生常谈 第一章: 1.什么是计算机网络?其主要功能是什么? 解答: 利用通信设备和线路,将分布在地理位置不同的、功能独立的多个计算机系统连接起来,以功能完善的网络软件实现网…...
【react】react创建项目与引入AntD组件库:
文章目录一、初始化项目:【1】创建项目【2】暴露项目配置文件【3】安装依赖【4】配置less二、快捷键:【1】rcctab三、安装AntD组件库:【1】安装【2】index.js【3】问题:【4】效果:一、初始化项目: 【1】创…...
hook与mixin
看完vue3就开始看vue3的源码,表示很懵~ 刚把rollup打包搞完,这不响应式就接着来了!,还是写篇直接使用vue3的博客清清脑吧! 什么是hook、mixin? mixin: Vue2中多个组件内存在重复JS业务逻辑,使…...
【C语言】自定义类型
一、什么是自定义类型C语言提供了丰富的内置类型,常见的有int, char, float, double, 以及各种指针。除此之外,我们还能自己创建一些类型,这些类型称为自定义类型,如数组,结构体,枚举类型和联合体类型。二、…...
没有上司的舞会(C++,树形DP)
题目描述 某大学有 nnn 个职员,编号为 1…n1\ldots n1…n。 他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。 现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 ri…...
【java基础】static和final关键字的作用及其用法详解
文章目录static关键字静态字段静态方法静态代码块静态内部类final关键字final字段final方法final类static关键字 这个关键字表示静态的,用于不同地方意思不一样 静态字段 如果我们将其作用到字段上,那么该字段为类所拥有,我们使用new关键字…...
#集成学习#:bagging、boosting、stacking和blending
集成学习是一种机器学习方法,旨在提高单个模型的性能和鲁棒性。它基于这样一个假设:通过结合多个模型的预测结果,可以获得更好的预测性能,因为每个模型都可能从数据中提取不同的信息,因此他们的错误也可能是不同的&…...
NCRE计算机等级考试Python真题(一)
第一套试题1、关于数据的存储结构,以下选项描述正确的是A.数据所占的存储空间量B.数据在计算机中的顺序存储方式C.数据的逻辑结构在计算机中的表示D.存储在外存中的数据正确答案: C2、关于线性链表的描述,以下选项中正确的是A.存储空间不一定…...
C#协变逆变
文章目录协变协变接口的实现逆变里氏替换原则协变 协变概念令人费解,多半是取名或者翻译的锅,其实是很容易理解的。 比如大街上有一只狗,我说大家快看,这有一只动物!这个非常自然,虽然动物并不严格等于狗…...
算法设计与分析期末考试复习(四)
贪心算法(Greedy Algorithm) 找零钱问题 假设有4种硬币,面值分别为:二角五分、一角、五分和一分,现在要找给顾客六角三分钱,如何找使得给出的硬币个数最少? 首先选出1个面值不超过六角三分的最…...
qsort函数排序数据 and 模拟实现qosrt函数(详解)
前言:内容包括使用库函数qsort排序任意类型的数据,模拟实现qsort函数(冒泡排序的逻辑) 我们先了解qsort函数的语法:qsort函数默认按照升序排序数据 void qsort (void* base, size_t num, size_t size,int (*compar)(…...
Mysql视图,存储过程,触发器,函数以及Mysql架构
一,视图视图是基于查询的一个虚拟表 , 也就是将sql语句封装起来, 要用的时候直接调用视图即可, select语句查询的表称为基表, 查询的结果集称为虚拟表, 基本表数据发生了改变, 那么视图也会发生改变, 使用视图就是为了简化查询语句.1.CREATE VIEW view_admin AS SELECT * FROM…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
CppCon 2015 学习:Time Programming Fundamentals
Civil Time 公历时间 特点: 共 6 个字段: Year(年)Month(月)Day(日)Hour(小时)Minute(分钟)Second(秒) 表示…...
麒麟系统使用-进行.NET开发
文章目录 前言一、搭建dotnet环境1.获取相关资源2.配置dotnet 二、使用dotnet三、其他说明总结 前言 麒麟系统的内核是基于linux的,如果需要进行.NET开发,则需要安装特定的应用。由于NET Framework 是仅适用于 Windows 版本的 .NET,所以要进…...
高效的后台管理系统——可进行二次开发
随着互联网技术的迅猛发展,企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心,成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统,它不仅支持跨平台应用,还能提供丰富…...
