【Linux网络编程】UDP Echo Server的实现
本文专栏:Linux网络编程
目录
一,Socket编程基础
1,IP地址和端口号
端口号划分范围
理解端口号和进程ID
源端口号和目的端口号
理解Socket
2,传输层的典型代表
3,网络字节序
4,Socket编程接口
sockaddr结构
二,Echo Server(UDP实现)
1,服务器端(server端)代码编写
创建套接字(socket)
绑定端IP和 端口号
接受消息(recvfrom)
发送消息
2,客户端(client端)代码编写
3,代码总体
4,现象演示
一,Socket编程基础
1,IP地址和端口号
IP地址:
- 定义:IP在网络中,用来标识主机的唯一性。或者说IP地址是分配给网络设备的唯一标识,用于在互联网中定位设备。
作用:
- 设备寻址:确保数据包从源设备发送到目标设备
- 路由选择:路由器根据IP地址决定数据包的转发路径。
端口号:
- 端口号是传输层协议的内容。
- 端口号是一个2字节,16为的整数。
- 端口号用来标识唯一进程,告诉操作系统,当前的这个数据要交给哪个进程来处理。
- 一个端口号只能 被一个进程占用。
所以IP地址+端口号能够标识网络上的某一台主机的某一个进程。
端口号划分范围
- 0-1023:是指明端口号,HTTP,SSH,FTP等广为使用的应用层协议,他们的端口号都是固定的。
- 1024-65535:是操作系统动态分配的端口号。客户端运行的程序,就是由操作系统从这个范围分配的。
理解端口号和进程ID
在操作系统中,我们知道pid表示唯一一个进程。而这里端口号也是表示唯一一个进程 。这两个之间有什么关系?
进程ID属于系统概念,技术上 也具有唯一性,确实可以用来标识唯一的一个进程 。但是如果让进程ID代替端口号,会让系统进程管理和网络强耦合 。
源端口号和目的端口号
传输层协议(TCP和UDP)的数据段中有两个端口号,分别叫做源端口号和目的端口号。
就是在 描述”数据是谁发的,要发给谁“。
理解Socket
- IP地址用来标识主机的唯一性,port端口号用来标识该台主机上 唯一的一个进程。
- 所以IP+port就能 表示互联网中唯一的一个进程。
- 所以,通信的时候,本质是两个互联网进程在通信,所以,网络通信的本质是进程间通信。
- 我们把IP+port叫做套接字(Socket)。
2,传输层的典型代表
传输层是属于内核的,所以进行网络通信,必定调用的是传输层提供的系统调用。
TCP协议:
- 传输层协议
- 有连接
- 可靠传输
- 面向字节流
UDP协议:
- 传输层协议
- 无连接
- 不可靠传输
- 面向数据报
3,网络字节序
内存中多字节数据相对于内存地址有大端和小端之分。
所谓小端,就是对于多字节的数据,它的低权值位存放在低地址处,高权值位存放在高地址处。大端与之相反,低权值位存放在高地址处,高权值位存放在低地址处 。
发送主机通常将发送的数据按内存地址从低到高发出。
接受主机把从网络上接受的数据依次保存在缓冲区,也是按内存地址从低到高的顺序保存的。
而不同的主机,它的存储序列可能不同,可能是大端存储,也有可能是小端存储。
如果两台机器的存储形式不同,一台是大端存储,另一台是小端存储,那么在接受数据的时候,就会将数据解释错了。
解决方法:于是就有了一个规定,发送到网络中的数据必须是大端形式的。
所以,不管这台主机 是大端序列还是小端序列,都会按照这个规定的网络字节序来发送/接受数据。
如果当前主机是小端,就需要先将数据转化为大端;如果是大端,就忽略。
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数来做主机字节序和网络字节序的转化:
- h表示host,n表示network,l表示32位长整数,s表示16位短整数。
- 例如htonl表示将32位的长整数从主机字节序转换为网络字节序。
- 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回。
- 如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。
4,Socket编程接口
常见API
C// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器 )int socket(int domain,int type,int protocol);
//绑定端口号(TCP/UDP,服务器)
int bind(int socket,const struct sockaddr* address,sock_lent addresslen);
//开始监听socket(TCP,服务器)
int listen(int socket,int backlog);
//接收请求(TCP,服务器)
int accept(int socket,struct sockaddr* address,sock_lent* addresslen);
//建立连接(TCP,客户端)
int connect(int sockfd,const struct sockaddr* addr,sock_lent* addrlen);
在上面的API接口中,sockaddr这个结构体经常出现。它是什么呢?
sockaddr结构
二,Echo Server(UDP实现)
Echo Server(回显服务器)是一种网络应用程序。其核心功能是接受客户端发来的数据,并将接受到的数据原样返回给客户端。
核心逻辑:
服务端
创建套接字 → 绑定地址 → 监听连接 → 接受请求 → 读取数据 → 回传数据。客户端
创建套接字 → 连接服务器 → 发送数据 → 接收回显数据。
不过我们实现的是UDP的,所以没有监听连接这一步。
1,服务器端(server端)代码编写
这里对服务器端代码编写时,会采用面向对象的思路,简单的进行封装。
大致框架:
class udpserver
{public:udpserver(uint16_t port):_port(port), _isrunning(false){}///~udpserver(){}private:int _sockfd;//套接字uint16_t _port;//端口号bool _isrunning;//是否在进行网络通信
};
下面就是正式对网络通信的代码编写:
首先,定义一个init方法,在该函数中,完成创建套接字和绑定的任务。
创建套接字(socket)
关于该函数的返回值 ,文档中的说明如下:
可以看出,该函数的返回值是一个文件描述符,-1表示失败,和文件系统中的open一样。所以可以简单的理解成创建套接字,在系统内部会打开一个文件,然后分配一个文件描述符。
//1,创建套接字_sockfd=socket(AF_INET,SOCK_DGRAM,0);if(_sockfd<0){std::cout<<"创建套接字失败"<<std::endl;exit(1);}std::cout<<"创建套接字成功"<<std::endl;
绑定端IP和 端口号
为当前服务器进程绑定端口号和IP地址。
前面讲过IP+端口号可以标识网络中某台主机上的唯一一个进程。
在绑定之前,需要我们填写addr这个结构体中的内容。
我们是进行网络通信,所以需要填写下图中的sockaddr_in结构体,有三个成员。最后的8字节用0填充即可。
我们在填写该结构体中的端口号时,考虑到不同机器的大小端存储形式可能不一样。所以需要先将 端口号转化为网络字节序,使用htons接口。
同时IP地址在填充的时候 ,还有一个问题,具体内容看下面代码的注释:
//2,绑定端口号和IP//填充sockarr_in信息struct sockaddr_in local;//先将结构体内容清0bzero(&local,sizeof(local));local.sin_family=AF_INET;//头部的16为,表示网络通信local.sin_port=htons(_port);//端口号//INADDR_ANY是一个宏,这个宏的值是0//可能存在多个客户端要访问该服务器进程//有的客户端拿着内网IP,有的客户端拿着本地回环IP 127.0.0.1访问该服务器进程//那么该服务器进程的IP就必须保持不变,是一个绑死的值,只有和该IP相等的客户端才能访问//将IP地址设为0的好处是://不同的客户端,拿着不同的IP访问该服务器进程,只要端口号和该进程相等,就都可以访问呢local.sin_addr.s_addr=INADDR_ANY;//IP地址int n=bind(_sockfd,(struct sockaddr*)&local,sizeof(local));if(n<0){std::cout<<"绑定失败"<<std::endl;exit(2);}std::cout<<"绑定成功"<<std::endl;
接受消息(recvfrom)
再定义一个start方法 ,来实现接受消息和发送消息。
- 第一个参数是创建的套接字
- 第二个参数和第三个参数是缓冲区及对应的大小,用来存放接受到的数据
- 第四个参数flags:该参数设置为0,表示阻塞式IO,如果对方 不发数据,该函数(进程)就会一致阻塞在这里等同于scanf
- 第五个参数:我们作为服务器端,需要知道是哪个主机的哪个进程发的数据,就存放在该结构体中。
- 最后一个参数:表示该结构体的大小
//缓冲区——存放消息
char buffer[1024];
//获取哪台主机的哪个进程发送的数据,可以理解为这是一个输出型参数
struct sockaddr_in peer;
socklen_t len=sizeof(peer);
//接受消息
//我们将接受到的消息是按字符串存储的
//这里sizeof(buffer)-1是为了保留最后一个位置填充1
ssize_t n=recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
注意:我们从网络中拿到了发送过来的数据,这些数据包括struct sockaddr结构体。
所以我们想要知道是哪台主机的哪个进程发送过来的,只要拿到该结构体中的IP和端口号即可。但是这些字段是从网络中来的,都是大端形式的。所以我们还需再做一步,将网络字节序转化为主机字节序,可以使用ntohs接口。
发送消息
服务器端接收到客户端发来的消息后,要进行出来后,再返回给客户端。也就是用户做了某个要要求,服务器端执行完后,返回给用户一个结果。
- 第一个参数:创建的套接字
- 第二个参数和第三个参数:发送数据的内容和长度
- 第四个参数:和上面接受消息的一样
- 最后两个参数:发送数据,需要知道是给谁发的,也就是目标主机的IP和端口号,这些内容存放于该结构体中
对于接受到的数据,进行处理,再返回给客户端一个返回结果。所以我们可以自定义一个处理函数,对接受到的数据执行某种方法,再将结果返回给用户。
//获取发送方的信息//获取端口号(客户端的)int peer_port=ntohs(peer.sin_port);//网络字节序转主机字节序//获取IP(点分十进制格式)//该函数做两个工作 1,将网络字节序转化为主机字节序 2,将主机字节序的IP再转化为点分十进制形式std::string peer_ip=inet_ntoa(peer.sin_addr);
buffer[n]=0;//接受到的数据//处理buffer,自定义一个函数
//产生一个处理结果,返回给发送方,也就是客户端std::string result=_func(buffer);//发送消息
sendto(_sockfd,result.c_str(),result.size(),0,(struct sockaddr*)&peer,len);
2,客户端(client端)代码编写
客户端代码编写与服务器端代码类似,比服务器端代码更简单。
客户端也需要创建套接字:
//以命令行参数的形式获取IP和端口号
int main(int argc, char *argv[])
{if (argc != 3){std::cerr << "Usage: " << argv[0] << " server_ip server_port" << std::endl;return 1;}std::string server_ip = argv[1];//IPuint16_t server_port = std::stoi(argv[2]);//端口号// 1. 创建socketint sockfd = socket(AF_INET, SOCK_DGRAM, 0);if(sockfd < 0){std::cerr << "socket error" << std::endl;return 2;}return 0;
}
但是客户端不需要显示的绑定端口号和IP了。当客户端尝试发送消息的时候,操作系统会为该客户端进程分配一个随机端口号,操作系统也知道本主机的IP地址,所以操作系统会在内部进行绑定。所以就不需要我们手动绑定了。
而为什么要这么做?
- 首先,一个端口号只能被一个进程绑定。
- 如果我们手动显示的绑定了,也就是我们把一个进程和一个端口号绑定在一起,绑死了。比如我们写了一个客户端,绑定一个端口号666,它没有运行。那么当再启动一个淘宝APP时,如果淘宝也绑定了这个端口号,那么我们的客户端进程就无法启动了。
- 所以,这样采用随机端口的方式,是为了避免client端口冲突的问题。
- 所以,客户端对应的端口号是多少不重要,只要是唯一的就行。
而为什么服务器端需要绑定?
- 首先,服务器肯定是被多个客户端进行访问的。
- 服务器的IP和端口号必须是众所周知且不能轻易改变的。
- 改变了,客户端就无法访问了。
这就好像再生活中,一些公共部门的电话是众所周知,且不能改变的,比如110,120,119等等。而我们的电话是可以改的。
所以创建套接字后,就可以发送消息了,不需要显示bind了。
发送消息,接受消息和服务器端的代码类似,这里不做过多赘述了。
3,代码总体
udpserver.hpp文件
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <functional>using func_t=std::function<std::string(const std::string&)>;
class udpserver
{public:udpserver(uint16_t port,func_t func):_port(port), _isrunning(false),_func(func){}//void init(){//1,创建套接字_sockfd=socket(AF_INET,SOCK_DGRAM,0);if(_sockfd<0){std::cout<<"创建套接字失败"<<std::endl;exit(1);}std::cout<<"创建套接字成功"<<std::endl;//2,绑定端口号和IP//填充sockarr_in信息struct sockaddr_in local;//先将结构体内容清0bzero(&local,sizeof(local));local.sin_family=AF_INET;//头部的16为,表示网络通信local.sin_port=htons(_port);//端口号//INADDR_ANY是一个宏,这个宏的值是0//可能存在多个客户端要访问该服务器进程//有的客户端拿着内网IP,有的客户端拿着本地回环IP 127.0.0.1访问该服务器进程//那么该服务器进程的IP就必须保持不变,是一个绑死的值,只有和该IP相等的客户端才能访问//将IP地址设为0的好处是://不同的客户端,拿着不同的IP访问该服务器进程,只要端口号和该进程相等,就都可以访问呢local.sin_addr.s_addr=INADDR_ANY;//IP地址int n=bind(_sockfd,(struct sockaddr*)&local,sizeof(local));if(n<0){std::cout<<"绑定失败"<<std::endl;exit(2);}std::cout<<"绑定成功"<<std::endl;}void start(){_isrunning=true;while(_isrunning){//缓冲区——存放消息char buffer[1024];//获取哪台主机的哪个进程发送的数据,可以理解为这是一个输出型参数struct sockaddr_in peer;socklen_t len=sizeof(peer);//接受消息//我们将接受到的消息是按字符串存储的//这里sizeof(buffer)-1是为了保留最后一个位置填充1ssize_t n=recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);if(n>0){//获取发送方的信息//获取端口号(客户端的)int peer_port=ntohs(peer.sin_port);//网络字节序转主机字节序//获取IP(点分十进制格式)//该函数做两个工作 1,将网络字节序转化为主机字节序 2,将主机字节序的IP再转化为点分十进制形式std::string peer_ip=inet_ntoa(peer.sin_addr);buffer[n]=0;//接受到的数据//处理buffer,自定义一个函数//产生一个处理结果,返回给发送方,也就是客户端std::string result=_func(buffer);//发送消息sendto(_sockfd,result.c_str(),result.size(),0,(struct sockaddr*)&peer,len);}}}/~udpserver(){}private:int _sockfd;//套接字uint16_t _port;//端口号bool _isrunning;//是否在进行网络通信func_t _func;//回调函数
};
udpserver.cpp文件
#include "udpserver.hpp"
#include <memory>std::string defaulthandler(const std::string &message)
{std::string hello = "hello, ";hello += message;return hello;
}//端口号以命令行参数的形式获取
int main(int argc, char *argv[])
{if(argc != 2){std::cerr << "Usage: " << argv[0] << " port" << std::endl;return 1;}uint16_t port = std::stoi(argv[1]);std::unique_ptr<udpserver> usvr = std::make_unique<udpserver>(port,defaulthandler);usvr->init();usvr->start();return 0;
}
udpclient.cpp文件
#include <iostream>
#include <string>
#include <cstring>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>//以命令行参数的形式获取IP和端口号
int main(int argc, char *argv[])
{if (argc != 3){std::cerr << "Usage: " << argv[0] << " server_ip server_port" << std::endl;return 1;}std::string server_ip = argv[1];//IPuint16_t server_port = std::stoi(argv[2]);//端口号// 1. 创建socketint sockfd = socket(AF_INET, SOCK_DGRAM, 0);if(sockfd < 0){std::cerr << "socket error" << std::endl;return 2;}// 填写服务器信息struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(server_port);server.sin_addr.s_addr = inet_addr(server_ip.c_str());while(true){std::string input;std::cout << "Please Enter# ";std::getline(std::cin, input);//发送消息int n = sendto(sockfd, input.c_str(), input.size(), 0, (struct sockaddr*)&server, sizeof(server));(void)n;char buffer[1024];struct sockaddr_in peer;socklen_t len = sizeof(peer);//接受消息int m = recvfrom(sockfd, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&peer, &len);if(m > 0){buffer[m] = 0;std::cout << buffer << std::endl;}}return 0;
}
4,现象演示
相关文章:
【Linux网络编程】UDP Echo Server的实现
本文专栏:Linux网络编程 目录 一,Socket编程基础 1,IP地址和端口号 端口号划分范围 理解端口号和进程ID 源端口号和目的端口号 理解Socket 2,传输层的典型代表 3,网络字节序 4,Socket编程接口 s…...
8.3.5 ToolStripContainer(工具栏容器)控件
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的 ToolStripContainer控件是一个容器,可以包含菜单和工具条、状态栏。 在设计窗体中放入一个ToolStripContainer࿱…...
代码随想录-06-二叉树-05.05 N叉树的层序遍历
N叉树的层序遍历 #模板题 题目描述 给定一个 N 叉树,返回其节点值的_层序遍历_。(即从左到右,逐层遍历)。 树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。 具体思路 …...
【NEPVR】《A Lightweight Palm Vein Recognition Algorithm NEPVR》
[1]马莉,刘子良,谭振林,等.一种轻量级掌静脉识别算法NEPVR[J].计算机技术与发展,2024,34(12):213-220.DOI:10.20165/j.cnki.ISSN1673-629X.2024.0248. 文章目录 1、背景2、相关工作3、创新点4、NEPVR 手掌静脉识别算法5、实验结果及分析6、总结 / 未来工作 1、背景 手掌静脉独…...
牟乃夏《ArcGIS Engine地理信息系统开发教程》学习笔记1
(适合GIS开发入门者,通俗解析核心知识点) 目录 一、ArcGIS Engine是什么? 二、ArcGIS Engine能做什么? 三、ArcGIS Engine与ArcObjects的区别 四、开发资源与学习路径 五、对象模型图(OMD)…...
架构师论文《论模型驱动软件开发方法在智能制造转型实践中的应用》
摘要: 本人现任某大型装备制造企业智能制造研究院首席架构师,主导集团级数字化工厂平台建设。面对多品种小批量生产模式下普遍存在的交付周期超预期(平均延期21天)、设备综合效率OEE不足65%的痛点,我司于2021年启动基…...
探索MCP.so:AI生态的创新枢纽
今天在研究MCP时发现了一个还不错的网站,分享给大家。后续会基于这些mcp servers做一些有趣的应用。 在人工智能飞速发展的当下,AI与各类工具、数据源的协同合作变得愈发关键。MCP.so这个平台,正悄然成为AI领域的重要枢纽,为众多开发者和AI爱好者打开了新的大门。 MCP,即…...
JVM底层详解
JVM底层详解 目录 JVM概述JVM内存模型垃圾回收机制类加载过程JIT编译JVM调优JVM监控与故障排查JVM与多线程JVM与性能优化JVM发展历程与未来JVM实战案例分析JVM高级特性JVM安全机制JVM与容器化 一、JVM概述 1.1 什么是JVM Java虚拟机(Java Virtual Machine&…...
多点:分布式升级助力新零售转型,成本节省超80% | OceanBase 案例
本文作者:多点数据库DBA团队 编者按:多点是零售行业数字(智)化的先行者,为全球企业提供创新的数字化解决方案。然而,在数字化转型的过程中,多点原有的数据库架构逐渐暴露出架构复杂、成本上升等…...
Java权限修饰符深度解析
Java权限修饰符深度解析与最佳实践 一、权限修饰符总览 Java提供四种访问控制修饰符,按访问范围从宽到窄排序如下: 修饰符类内部同包类不同包子类全局范围public✔️✔️✔️✔️protected✔️✔️✔️❌默认(无)✔️✔️❌❌pr…...
RocketMQ和kafka 的区别
一、数据可靠性与容错机制 数据可靠性 RocketMQ支持同步刷盘和同步复制,确保消息写入磁盘后才返回确认,单机可靠性高达10个9,即使操作系统崩溃也不会丢失数据159。而Kafka默认采用异步刷盘和异步复制,虽然吞吐量高,但极…...
分布式限流器框架 eval-rate-limiter
分布式限流器框架 eval-rate-limiter 文章目录 分布式限流器框架 eval-rate-limiter前言设计流程图 核心方法tryAcquire 获取通信证增加访问次数 incrementRequestCount生成分布式 key generateRateLimiterKey 测试测试代码结果Redis 客户端 前言 基于 redis 实现的分布式限流…...
使用Docker部署Java项目的完整指南
前言 Docker是一个轻量级的容器化平台,可将应用及其依赖打包成标准化单元,实现快速部署和环境隔离。本文以Spring Boot项目为例,演示如何通过Dockerfile部署Java应用。 准备工作 本地环境 安装Docker Desktop(官网下载࿰…...
机器学习数据需求与应用分析
监督学习、无监督学习和强化学习作为机器学习的核心范式,对数据条件的需求存在显著差异。以下是具体分析: 一、监督学习的数据条件 数据要求 监督学习需要带标签(labeled)的数据集,即每个输入样本都有对应的目标输出&a…...
【机器学习算法】基于python商品销量数据分析大屏可视化预测系统(完整系统源码+数据库+开发笔记+详细启动教程)✅
目录 一、项目背景 二、技术思路 三、算法介绍 四、项目创新点 五、开发技术介绍 六、项目展示 一、项目背景 本项目基于Python技术栈构建了"商品销量数据分析与预测系统",通过自动化爬取淘宝商品多维数据(价格、销量、评价、品类等&a…...
springboot集成springcloud vault读值示例
接上三篇 Vault---机密信息管理工具安装及常用示例 Vault机密管理工具集群配置示例 vault签发根证书、中间证书、ca证书流程记录 项目里打算把所有密码都放到vault里管理,vault提供了springcloud vault用来在springboot里连接vault,启动加载vault里的值放…...
BERT 模型是什么
BERT 模型是什么? BERT(Bidirectional Encoder Representations from Transformers)是一种基于Transformer架构的深度学习模型,由Google于2018年提出。它在自然语言处理领域取得了显著成就,成为众多NLP任务的基础。 …...
三元电池正极材料除杂工艺介绍
三元电池正极材料的除杂工艺对于提高电池性能、安全性和稳定性至关重要。以下是对三元电池正极材料除杂工艺的详细介绍: 物理除杂工艺 磁选 原理:利用磁场对磁性杂质的吸引作用实现分离。在三元电池正极材料生产中,常混入铁、钴、镍等磁性金…...
wx212基于ssm+vue+uniapp的科创微应用平台小程序
开发语言:Java框架:ssmuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:M…...
Multi Agents Collaboration OS:数据与知识协同构建数据工作流自动化
1-背景 传统数据系统与业务数字化的开发与维护面临诸多挑战:行业知识获取壁垒高、需求变化快导致开发周期长、系统复杂度高以及人力与资源投入成本巨大。同时,用户在使用过程中也常遇到痛点:手动录入数据繁琐低效、数据分散于各模块难以整合…...
elemenPlus中,如何去掉el-input中 文本域 textarea自带的边框和角标
1、去掉角标 :deep(.el-textarea__inner) {resize: none !important; // 去除右下角图标 }2、去除边框,并自定义背景色 <el-inputref"textareaRef"v-model"tempContent":style"{--el-border-color: rgba(255,255,255,0.0),--el-input-…...
Excel 动态比较两列数据:实现灵活的数据验证
目录 动态比较两列数据的需求动态公式的实现使用INDIRECT和ROW函数公式解释应用 动态公式的优点 快速添加一列公式的技巧使用快捷键Ctrl D使用VBA宏自动化使用“表格”功能自动填充 实际应用场景数据验证动态报告数据清洗 注意事项总结 在数据处理和分析中,Excel 是…...
谷歌推出可免费使用的Firebase Studio:Gemini全栈AI开发利器
谷歌刚刚发布了Firebase Studio,这是其打造的一款沉浸式代码开发平台,旨在与Cursor、Lovable、Bolt和V0等工具竞争。如果你是一名网页开发者,可能只知道Firebase是谷歌的数据库工具。 但现在,它已远不止于此。 Firebase已发展成一个完整的生态系统,如今能帮助你从头到尾…...
spark(二)
本节课接上节课继续对于RDD进行学习,首先是对于创建RDD的不同方式,接着学习了RDD的三种转换算子:Value类型、双Value类型、Key-Value类型,以及各个转换算子的不同使用方式。 学习到如下的区别: map 与 mapPartitions…...
Fay 数字人部署环境需求
D:\ai\Fay>python main.py pygame 2.6.1 (SDL 2.28.4, Python 3.11.9) Hello from the pygame community. https://www.pygame.org/contribute.html [2025-04-11 00:10:16.7][系统] 注册命令... [2025-04-11 00:10:16.8][系统] restart 重启服务 [2025-04-11 00:10:16.8][…...
【Harmony】端云一体化(云函数)
一、云函数的概述 1、什么是云函数 官方解释 云函数是一项Serverless计算服务,提供FaaS(Function as a Service)能力,一方面云函数将开发测试的对象聚焦到函数级别,可以帮助您大幅简化应用开发与运维相关的事务&…...
利用大模型和聚类算法找出 Excel 文件中重复或相似度高的数据,并使用 FastAPI 进行封装的详细方案
以下是一个利用大模型和聚类算法找出 Excel 文件中重复或相似度高的数据,并使用 FastAPI 进行封装的详细方案: 方案流程 数据读取:从 Excel 文件中读取数据。文本向量化:使用大模型将文本数据转换为向量表示。聚类分析:运用聚类算法对向量进行分组,将相似度高的数据归为…...
通过远程桌面连接wsl2中安装的ubuntu24.04
要介绍的这种方式其实跟直接用wsl来执行命令差不多,是在终端去操作ubuntu。WSL2 默认只提供命令行界面,本文安装xrdp后通过windows远程桌面连接过去。 1、更新软件包列表 sudo apt update 确保你的软件包列表是最新的,否则可能找不到某些包…...
对接和使用国内稳定无水印的 Suno API
随着 AI 的应用日益广泛,各种 AI 程序已经融入我们的日常生活。从最早的写作,到医疗、教育,如今甚至扩展到了音乐领域。 Suno 是一个专注于高质量 AI 歌曲和音乐创作的平台。用户只需输入简单的文本提示词,便可以按照流派风格和歌…...
LeetCode算法题(Go语言实现)_38
我将按照您提供的文档结构为您整理二叉树最近公共祖先(LCA)问题的解决方案: 一、代码实现 type TreeNode struct {Val intLeft *TreeNodeRight *TreeNode }func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {if root nil ||…...
Linux学习笔记 1
1.发展史 略...... 2.xshell的使用方法 2.1登录 ssh root公网地址 输入密码,用 uname -r 指令来鉴定是否登录成功。之后就可以进行命令行操作了。 alt enter 全屏、退出 设置多用户指令,新建用户 adduser 名字 passwd 密码 销毁用户…...
微信小程序跳4
formatMillisecondsTime: function(milliseconds, formatStr) { // 创建一个新的Date对象,传入毫秒值 const date new Date(milliseconds); // 获取年月日时分秒,并确保它们都是两位数 const year date.getFullYear(); const month (date.getMonth() …...
STM32单片机入门学习——第31节: [10-1] I2C通信协议
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.10 STM32开发板学习——第31节: [10-1] I2C通信协议 前言开发板说明引用解答和科普一…...
OpenCV 图形API(24)图像滤波-----双边滤波函数bilateralFilter()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 应用双边滤波到图像。 该函数对输入图像应用双边滤波,如 http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Fil…...
【图像处理基石】什么是影调?并用python实现一个哈苏色彩影调
影调是摄影语言的核心,通过控制明暗、虚实与色彩,可精准传达创作意图。实际选择需结合主题情感、光线条件及画面结构,灵活运用高调、低调或冷暖色调,以强化视觉表现力。 一、影调的定义 影调指画面中明暗、虚实、色彩的层次与对比…...
MySQL行列转换
创建一个sc表并插入数据 方法一: select distinct uid, (select score from sc where s.uiduid and course语文)语文, (select score from sc where s.uiduid and course数学)数学, (select score from sc where s.uiduid and course英语)英语 from sc s; 方法二: select * fro…...
cookie和session哪个生成的时间早
Cookie 和 Session 的出现时间都可以追溯到 Web 开发的早期阶段,但它们的生成顺序在实际应用中通常是先生成 Session,然后通过 Cookie 来存储 Session ID。 详细解释: Session 的生成过程 • 用户请求服务器: • 用户首次访问网…...
sh脚本删除指定后缀.txt的文件,保留6个月的数据
1、linux下脚本删除指定后缀.txt和.path的文件,保留6个月的数据: 下面代码内容: #!/bin/bash # 指定要删除文件的路径列表 paths("/data/fail")# 获取当前系统日期6个月之前的日期 six_months_ago$(date -d "-6 months"…...
嵌入式Linux按键监控模块详解:实现设备重启与长按检测
嵌入式Linux按键监控模块详解:实现设备重启与长按检测 在嵌入式Linux设备开发中,物理按键仍然是用户与设备交互的重要方式。本文将分享一个轻量级但功能完整的按键监控模块,它可以精确识别按键的短按和长按事件,并执行对应操作如…...
[错误经验 坑]关于UDP服务器和客户端通信使用的recvfrom的输出型参数len没有被初始化导致的问题
[错误经验 坑]关于UDP服务器和客户端通信使用的recvfrom的输出型参数len没有被初始化导致的问题 水墨不写bug 文章目录 一、困惑:二、解答:(1)函数原型1. int sockfd2. void *buf3. size_t len4. int flags5. struct sockaddr *sr…...
KaiwuDB:面向AIoT场景的多模融合数据库,赋能企业数字化转型
引言 在万物互联的AIoT时代,企业面临着海量时序数据处理、多模数据融合和实时分析等挑战。KaiwuDB应运而生,作为一款面向AIoT场景的分布式、多模融合、支持原生AI的数据库产品,为企业提供了一站式数据管理解决方案。 产品概述 KaiwuDB是一…...
Web3 的云基础设施正在成型,Polkadot 2.0 用三项技术改写“上链成本”
在Web3基础设施内卷加剧的今天,“如何以更低成本、更大灵活性部署一条高性能应用链”正成为开发者们最关心的问题。而刚刚走出“技术慢热”误区的Polkadot,正在用一套名为 Polkadot 2.0 的架构升级方案,重新定义这一问题的解法。 这套升级最…...
Elasticsearch 学习规划
Elasticsearch 学习规划 明确学习目标与动机 场景化需求分析 - **S**:掌握Elasticsearch架构体系,熟练使用Elasticsearch 进行数据分析,Elasticsearch结合java 项目落地案例 - **M**:搜索和Elasticsearch相关GitHub项目 - **A**:每…...
OpenHarmony如何编译安装系统应用(以settings设置为例)
开发环境 1.OpenHarmony 2.DevEco Studio 3 .Full Sdk 实现步骤 1.获取设置应用源码 https://gitee.com/openharmony/applications_settings/tree/OpenHarmony-v5.0.0-Release/ 2,使用 DevEco Studio 和 Full SDK对系统应用进行签名,默认工程是未配置签名的状态,所构建…...
手撕 STL 之—— list
目录 引言 1, list_node类及其构造函数 2, list类的创建 3, list基本功能函数 3_1, 构造函数 3_2,push_back 3_3,push_front 3_4, pop_back 3_5,pop_front 4,迭代器 (重点) 4_1,如何设…...
Med-R1论文阅读理解
论文介绍 这篇论文介绍了一个名为 Med-R1 的新方法,用于提升多模态视觉语言模型(VLM)在医学图像理解和推理任务中的泛化能力和可解释性。下面是对整篇论文的简洁总结: ⸻ 🧠 核心思想 • 当前医学 VLM 多依赖于监督…...
微服务相关
1.SpringCloud有哪些常用组件?分别是什么作用? 注册中心:nacos 负载均衡:rabbion/LoadBalancer 网关:gateway 服务熔断:sential 服务调用:Feign 2.服务注册发现的基本流程是怎样的&#x…...
Linux vagrant 导入Centos到virtualbox
前言 vagrant 导入centos 虚拟机 前提要求 安装 virtualbox 和vagrant<vagrant-disksize> (Linux 方式 Windows 方式) 创建一键部署centos 虚拟机 /opt/vagrant 安装目录/opt/VirtualBox 安装目录/opt/centos8/Vagrantfile (可配置网络IP,内存…...
Spring Boot MongoDB 分页工具类封装 (新手指南)
Spring Boot MongoDB 分页工具类封装 (新手指南) 目录 引言:为何需要分页工具类?工具类一:PaginationUtils - 简化 Pageable 创建 设计目标代码实现 (PaginationUtils.java)如何使用 PaginationUtils 工具类二:PageResponse<…...