Linux网络套接字之UDP网络程序
(。・∀・)ノ゙嗨!你好这里是ky233的主页:这里是ky233的主页,欢迎光临~
https://blog.csdn.net/ky233?type=blog
点个关注不迷路⌯'▾'⌯
实现一个简单的对话发消息的功能!
目录
一.新增的接口:
1.socket
2.bing
3.inet_addr
4.recvform
5.inet_ntoa
5.sendto
6.popen
二、初步代码以及结果
1.udp_server.hpp
2.udp_server.cc
3.udp_client
4.log.hpp
5.结果
三、爆改多线程
1.udp_client.cc
2.udp_server.cc
3.udp_server.hpp
4.thread.hpp
5.结果
一.新增的接口:
1.socket
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>int socket(int domain, int type, int protocol);
- 参数一:叫做域,用来判断是那个类型的,AF_UNIX, AF_LOCAL(用于本地通信)AF_INET(用于ipv4的网络通信)
- 参数二:类型,通信的种类是什么,SOCK_DGRAM(套接字的类别,数据报的方式)
- 参数三:协议,比如用AF_INET,SOCK_DGRAM,一般直接写0
- 创建成功会得到一个文件描述符,失败返回-1
2.bing
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
- 参数一:创建的套接字
- 参数二:填充sockaddr结构体
- 参数三:所传入这个结构体对象的长度
3.inet_addr
#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>
n_addr_t inet_addr(const char *cp);
- 将点分十进制转换成四字节,并且将主机序列转换成网络序列
- 参数一:传入的ip
4.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);
- 用于从套接字接收数据。该函数通常与无连接的数据报服务
- 参数一:套接字
- 参数二和参数三:读取数据的缓冲区,用于存放读取到的数据,len叫做最终的大小
- 参数四:读取的方式,0为阻塞的方式读取
- 参数五和参数六:是输出型参数,我们还要知道是谁给我们发的消息
5.inet_ntoa
#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>
char *inet_ntoa(struct in_addr in);
- 将点分四字节转换成点分十进制,并且将网络序列转换成主机序列
- 参数一:从网络中获取到的ip
5.sendto
#include <sys/types.h>
#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);
- 参数一:套接字
- 参数二和参数三:要发送的数据和长度
- 参数四:默认为0,阻塞
- 参数五:要把数据发给谁,
- 参数六:这个缓冲区的长度是多少
6.popen
#include <stdio.h>FILE *popen(const char *command, const char *type);
二、初步代码以及结果
1.udp_server.hpp
#ifndef _UDP_SERVER_HPP
#define _UDP_SERVER_HPP#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include "log.hpp"
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <cstdio>
#include <unistd.h>#define SIZE 1024class UDPServer
{
public:UDPServer(uint16_t port,std::string ip=""):port_(port),ip_(ip),sock_(-1){}bool initServer(){//这里开始使用网络部分//1.创建套接字sock_=socket(AF_INET,SOCK_DGRAM,0);if(sock_<0){logMessage(FATAL,"%d:%s",errno,strerror(errno));exit(2);}//2.bind绑定:将用户设置的ip和端口号在内核中和我们的进程强关联//"192.168.1.0"->点分十进制//以.来分隔,每个区域的取值范围为0——255,//正好为1字节,四个区域理论上需要四字节//所以我们的看的时候会由4字节显示,转换为点分十进制//初始化结构体完成struct sockaddr_in local;bzero(&local,sizeof(local));//填充结构体local.sin_family=AF_INET;//服务器的IP和端口号,未来也是要发送给对方主机才能互相通信的//所以要先把数据发送到网络,要用htonslocal.sin_port=htons(port_);//同上要先把点分十进制转换成四字节ip//还需要要把四字节主机序列,转换成网络序列//所以用inet_addr一次性转成网络四字节序列//local.sin_addr.s_addr=inet_addr(ip_.c_str());//一般情况下,只要是这个端口的,那么我们就直接全部都接受,而不是指定端口local.sin_addr.s_addr = ip_.empty() ? INADDR_ANY : inet_addr(ip_.c_str());//这里需要做强转,因为bind需要的是sockaddr类型而不是sockaddr_in类型if(bind(sock_,(struct sockaddr*)&local,sizeof(local))<0){logMessage(FATAL,"%d:%s",errno,strerror(errno));exit(2);}//至此初始化服务器写完,首先创建套接字,接着用bind来绑定ip和端口号写进内核中logMessage(NORMAL, "init udp server done ... %s", strerror(errno));return true;}void strat(){//作为一款网络服务器,是永远不退出的!// 服务器启动-> 进程 -> 常驻进程 -> 永远在内存中存在,除非挂了!//echo服务器,主机给我们发送消息,我们原封不动的返回char buffer[SIZE];for( ; ;){//1.读取数据//注意peer,纯输出型参数struct sockaddr_in peer;bzero(&peer,sizeof(peer));//输入:peer 缓冲区大小//输入:实际读到的peer大小//所以len的大小要为实际的peer大小socklen_t len = sizeof(peer);//这样就把数据读取到buffer里了ssize_t s= recvfrom(sock_,&buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);if(s>0){buffer[s]=0;//我们目前数据当作字符串//1.输出发送的数据信息//2.是谁?提取!uint16_t cil_port=ntohs(peer.sin_port);//从网络中来的,所以要进行转成主机端口号std::string cli_p=inet_ntoa(peer.sin_addr);//将点分四字节转换成点分十进制,并且将网络序列转换成主机序列printf("[%s:%d]# %s\n",cli_p.c_str(),cil_port,buffer);}//2.分析和处理数据//3.写回数据sendto(sock_,buffer,sizeof(buffer),0,(struct sockaddr*)&peer,len);}}~UDPServer(){if(sock_>=0){close(sock_);}}private:
uint16_t port_;
std::string ip_;
int sock_;
};#endif
2.udp_server.cc
#include "udp_server.hpp"
#include <memory>
#include <cstdlib>static void usage(std::string proc)
{std::cout << "\nUsage: " << proc << " port\n" << std::endl;
}int main(int argc,char *argv[])
{//检查传入ip和端口号是否错误if(argc!=2){usage(argv[0]);exit(1);}//初始化服务器,利用unique_ptruint16_t port=atoi(argv[1]);//std::string ip=argv[1];std::unique_ptr<UDPServer> svr(new UDPServer(port));svr->initServer();svr->strat();return 0;
}
3.udp_client
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <memory>
#include "thread.hpp"static void usage(std::string proc)
{std::cout << "\nUsage: " << proc << " serverIp serverPort\n"<< std::endl;
}int main(int argc, char *argv[])
{if (argc != 3){usage(argv[0]);exit(1);}int sock = socket(AF_INET, SOCK_DGRAM, 0);if (sock < 0){std::cerr << "socket error" << std::endl;exit(2);}//client要不要bind?要bind,但是client不会显示的bind,程序员不会自己bind//client是一个客户端,是普通人下载并使用的//如果需要显示的bind,也就要求了客户端也bind了一个固定的端口//万一其他的客户端提前真用了端口号了呢,这时这个客户端就无法启动了//所以不用显示的bind指定端口号,直接让OS自动随机选择std::string message;//给谁发的信息如下struct sockaddr_in server;memset(&server,0,sizeof(server));server.sin_family=AF_INET;server.sin_port=htons(atoi(argv[2]));server.sin_addr.s_addr=inet_addr(argv[1]);char buffer[1024];while(1){std::cout<<"请输入你的信息# ";std::getline(std::cin,message);if(message=="quit"){break;}//当client首次发送消息给服务器的时候,OS会自动给client bind它的ip和portsendto(sock,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));//至此客户端和服务器已经建成//这里需要定义两个占位的struct sockaddr_in temp;socklen_t len = sizeof(temp);ssize_t s= recvfrom(sock,&buffer,sizeof(buffer)-1,0,(struct sockaddr*)&temp,&len);if(s>0){buffer[s]=0;std::cout<<"server echo# "<<buffer<<std::endl;}}close(sock);return 0;
}
4.log.hpp
#pragma once#include <iostream>
#include <cstdio>
#include <cstdarg>
#include <ctime>
#include <string>// 日志是有日志级别的
#define DEBUG 0
#define NORMAL 1
#define WARNING 2
#define ERROR 3
#define FATAL 4const char *gLevelMap[] = {"DEBUG","NORMAL","WARNING","ERROR","FATAL"
};#define LOGFILE "./threadpool.log"// 完整的日志功能,至少: 日志等级 时间 支持用户自定义(日志内容, 文件行,文件名)
void logMessage(int level, const char *format, ...)
{
#ifndef DEBUG_SHOWif(level== DEBUG) return;
#endif// va_list ap;// va_start(ap, format);// while()// int x = va_arg(ap, int);// va_end(ap); //ap=nullptrchar stdBuffer[1024]; //标准部分time_t timestamp = time(nullptr);// struct tm *localtime = localtime(×tamp);snprintf(stdBuffer, sizeof stdBuffer, "[%s] [%ld] ", gLevelMap[level], timestamp);char logBuffer[1024]; //自定义部分va_list args;va_start(args, format);// vprintf(format, args);vsnprintf(logBuffer, sizeof logBuffer, format, args);va_end(args);//FILE *fp = fopen(LOGFILE, "a");printf("%s%s\n", stdBuffer, logBuffer);//fprintf(fp, "%s%s\n", stdBuffer, logBuffer);//fclose(fp);
}
5.结果
这个叫做本地环回:client和server发送数据只在本地协议栈中进行数据流动,不会把我们的数据发送到网络中,通常用于本地网络服务器的测试
——————————————————————————————————————————


其中客户端时OS随机绑定的,全0IP是因为只要是这个端口的我都要,不要具体IP的
三、爆改多线程
我们要把这个代码改成一个类似QQ群一样的模式,所有人发的消息都可以看到
1.udp_client.cc
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <memory>
#include "thread.hpp"uint16_t serverport=0;
std::string serverip;//发现:无论是多线程读还是写,用的sock都是一个,sock代表就是文件,UDP是全双工的-> 可以同时进行收发而不受干扰static void usage(std::string proc)
{std::cout << "\nUsage: " << proc << " serverIp serverPort\n"<< std::endl;
}//发送逻辑的回调
static void *udpSend(void *args)
{//根据线程的封装,先转换成data*的然后获取里面的args_,然后在转会int*//获得一个指针指向args里面的sock,然后解引用int sock=*(int*)((ThreadData*)args)->args_;std::string name = ((ThreadData*)args)->name_;//下面逻辑与之前一样,构建发送的字符串,套接字信息std::string message;//给谁发的信息如下struct sockaddr_in server;memset(&server,0,sizeof(server));server.sin_family=AF_INET;server.sin_port=htons(serverport);server.sin_addr.s_addr=inet_addr(serverip.c_str());//开始不间断的发送while(1){std::cerr<<"请输入你的信息# ";std::getline(std::cin,message);if(message=="quit"){break;}//当client首次发送消息给服务器的时候,OS会自动给client bind它的ip和portsendto(sock,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));//至此客户端和服务器已经建成}return nullptr;
}//接受逻辑的回调
static void *udpRecv(void *args)
{int sock=*(int*)((ThreadData*)args)->args_;std::string name = ((ThreadData*)args)->name_;//需要不断地去读,要去指定的套接字中读取while(1){char buffer[1024];struct sockaddr_in temp;socklen_t len = sizeof(temp);ssize_t s= recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&temp,&len);if(s>0){buffer[s]=0;std::cout<<buffer<<std::endl;}}
}int main(int argc, char *argv[])
{if (argc != 3){usage(argv[0]);exit(1);}int sock = socket(AF_INET, SOCK_DGRAM, 0);if (sock < 0){std::cerr << "socket error" << std::endl;exit(2);}serverport=atoi(argv[2]);serverip=argv[1];//client要不要bind?要bind,但是client不会显示的bind,程序员不会自己bind//client是一个客户端,是普通人下载并使用的//如果需要显示的bind,也就要求了客户端也bind了一个固定的端口//万一其他的客户端提前真用了端口号了呢,这时这个客户端就无法启动了//所以不用显示的bind指定端口号,直接让OS自动随机选择//爆改多线程,一个线程发送数据到各个主机,一个线程接受各个数据。std::unique_ptr<Thread> sender(new Thread(1,udpSend,(void*)&sock));std::unique_ptr<Thread> recver(new Thread(2,udpRecv,(void*)&sock));sender->start();recver->start();sender->join();recver->join();close(sock);// std::string message;// //给谁发的信息如下// struct sockaddr_in server;// memset(&server,0,sizeof(server));// server.sin_family=AF_INET;// server.sin_port=htons(atoi(argv[2]));// server.sin_addr.s_addr=inet_addr(argv[1]);// char buffer[1024];// while(1)// {// std::cout<<"请输入你的信息# ";// std::getline(std::cin,message);// if(message=="quit")// {// break;// }// //当client首次发送消息给服务器的时候,OS会自动给client bind它的ip和port// sendto(sock,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));// //至此客户端和服务器已经建成// //这里需要定义两个占位的// struct sockaddr_in temp;// socklen_t len = sizeof(temp);// ssize_t s= recvfrom(sock,&buffer,sizeof(buffer)-1,0,(struct sockaddr*)&temp,&len);// if(s>0)// {// buffer[s]=0;// std::cout<<"server echo# "<<buffer<<std::endl;// }// }// close(sock);return 0;
}
2.udp_server.cc
#include "udp_server.hpp"
#include <memory>
#include <cstdlib>static void usage(std::string proc)
{std::cout << "\nUsage: " << proc << " port\n" << std::endl;
}int main(int argc,char *argv[])
{//检查传入ip和端口号是否错误if(argc!=2){usage(argv[0]);exit(1);}//初始化服务器,利用unique_ptruint16_t port=atoi(argv[1]);//std::string ip=argv[1];std::unique_ptr<UDPServer> svr(new UDPServer(port));svr->initServer();svr->strat();return 0;
}
3.udp_server.hpp
#ifndef _UDP_SERVER_HPP
#define _UDP_SERVER_HPP#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include "log.hpp"
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <cstdio>
#include <unistd.h>
#include <unordered_map>#define SIZE 1024class UDPServer
{
public:UDPServer(uint16_t port, std::string ip = ""): port_(port), ip_(ip), sock_(-1){}bool initServer(){// 这里开始使用网络部分// 1.创建套接字sock_ = socket(AF_INET, SOCK_DGRAM, 0);if (sock_ < 0){logMessage(FATAL, "%d:%s", errno, strerror(errno));exit(2);}// 2.bind绑定:将用户设置的ip和端口号在内核中和我们的进程强关联//"192.168.1.0"->点分十进制// 以.来分隔,每个区域的取值范围为0——255,// 正好为1字节,四个区域理论上需要四字节// 所以我们的看的时候会由4字节显示,转换为点分十进制// 初始化结构体完成struct sockaddr_in local;bzero(&local, sizeof(local));// 填充结构体local.sin_family = AF_INET;// 服务器的IP和端口号,未来也是要发送给对方主机才能互相通信的// 所以要先把数据发送到网络,要用htonslocal.sin_port = htons(port_);// 同上要先把点分十进制转换成四字节ip// 还需要要把四字节主机序列,转换成网络序列// 所以用inet_addr一次性转成网络四字节序列// local.sin_addr.s_addr=inet_addr(ip_.c_str());// 一般情况下,只要是这个端口的,那么我们就直接全部都接受,而不是指定端口local.sin_addr.s_addr = ip_.empty() ? INADDR_ANY : inet_addr(ip_.c_str());// 这里需要做强转,因为bind需要的是sockaddr类型而不是sockaddr_in类型if (bind(sock_, (struct sockaddr *)&local, sizeof(local)) < 0){logMessage(FATAL, "%d:%s", errno, strerror(errno));exit(2);}// 至此初始化服务器写完,首先创建套接字,接着用bind来绑定ip和端口号写进内核中logMessage(NORMAL, "init udp server done ... %s", strerror(errno));return true;}void strat(){// 作为一款网络服务器,是永远不退出的!// 服务器启动-> 进程 -> 常驻进程 -> 永远在内存中存在,除非挂了!// echo服务器,主机给我们发送消息,我们原封不动的返回char buffer[SIZE];for (;;){// 1.读取数据// 注意peer,纯输出型参数struct sockaddr_in peer;bzero(&peer, sizeof(peer));// 输入:peer 缓冲区大小// 输入:实际读到的peer大小// 所以len的大小要为实际的peer大小socklen_t len = sizeof(peer);// 这样就把数据读取到buffer里了ssize_t s = recvfrom(sock_, &buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);char result[256];char key[64];std::string cmd_echo;if (s > 0){buffer[s] = 0; // 我们目前数据当作字符串// 1.输出发送的数据信息// 2.是谁?提取!// if(strcasestr(buffer,"rm")!=nullptr||strcasestr(buffer,"rmdir")!=nullptr)// {// std::string err_message="坏人";// std::cout<<err_message<<buffer<<std::endl;// sendto(sock_, err_message.c_str(), err_message.size(), 0, (struct sockaddr *)&peer, len);// continue;// }// FILE *fp = popen(buffer, "r");// if (nullptr == fp)// {// logMessage(ERROR, "%d:%s", errno, strerror(errno));// continue;// }// while (fgets(result, sizeof(result), fp) != nullptr)// {// cmd_echo += result;// }// fclose(fp);uint16_t cil_port = ntohs(peer.sin_port); // 从网络中来的,所以要进行转成主机端口号std::string cil_ip = inet_ntoa(peer.sin_addr); // 将点分四字节转换成点分十进制,并且将网络序列转换成主机序列// printf("[%s:%d]# %s\n",cli_p.c_str(),cil_port,buffer);snprintf(key, sizeof(key), "%s-%d", cil_ip.c_str(), cil_port);logMessage(NORMAL,"key: %s",key);auto it = users_.find(key);if(it==users_.end()){logMessage(NORMAL,"add new user:%s",key);users_.insert({key,peer});}}// 2.分析和处理数据// 3.写回数据// sendto(sock_,buffer,sizeof(buffer),0,(struct sockaddr*)&peer,len);//sendto(sock_, cmd_echo.c_str(), cmd_echo.size(), 0, (struct sockaddr *)&peer, len);for(auto &iter:users_){std::string sendMessage=key;sendMessage+="# ";sendMessage+=buffer;logMessage(NORMAL,"push message to %s",iter.first.c_str());sendto(sock_, sendMessage.c_str(), sendMessage.size(), 0, (struct sockaddr *)&(iter.second), sizeof(iter.second));}}}~UDPServer(){if (sock_ >= 0){close(sock_);}}private:uint16_t port_;std::string ip_;int sock_;std::unordered_map<std::string, struct sockaddr_in> users_;
};#endif
4.thread.hpp
#pragma once
#include <iostream>
#include <string>
#include <functional>
#include <cstdio>using namespace std;typedef void*(*fun_t)(void*);class ThreadData
{
public:void* args_;string name_;
};class Thread
{
public:Thread(int num,fun_t callback,void* args):func_(callback){char namebuffer[64];snprintf(namebuffer,sizeof(namebuffer),"Thread-%d",num);name_=namebuffer;tdata_.args_=args;tdata_.name_=name_;}void start(){pthread_create(&tid_,nullptr,func_,&tdata_.args_);}void join(){pthread_join(tid_,nullptr);}string name(){return name_;}~Thread(){}private:string name_;fun_t func_;ThreadData tdata_;pthread_t tid_;
};
5.结果
利用管道可以更好的观看

相关文章:
Linux网络套接字之UDP网络程序
(。・∀・)ノ゙嗨!你好这里是ky233的主页:这里是ky233的主页,欢迎光临~https://blog.csdn.net/ky233?typeblog 点个关注不迷路⌯▾⌯ 实现一个简单的对话发消息的功能! 目录…...
Apache POI 解析和处理Excel
摘要:由于开发需要批量导入Excel中的数据,使用了Apache POI库,记录下使用过程 1. 背景 Java 中操作 Excel 文件的库常用的有Apache POI 和阿里巴巴的 EasyExcel 。Apache POI 是一个功能比较全面的 Java 库,适合处理复杂的 Offi…...
SQL 注入攻击 - insert注入
环境准备:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客 一、注入原理 描述:insert注入是指通过前端注册的信息被后台通过insert操作插入到数据库中。如果后台没有做相应的处理,就可能导致insert注入漏洞。原因:后台未对用户输入进行充…...
第一个 Angular 项目 - 添加路由
第一个 Angular 项目 - 添加路由 前置项目是 第一个 Angular 项目 - 添加服务,之前的切换页面使用的是 ngIf 对渲染的组件进行判断,从而完成渲染。这一步的打算是添加路由,同时添加 edit recipe 的功能(同样通过路由实现) 用到的内容为&…...
如何简洁高效的搭建一个SpringCloud2023的maven工程
前言 依赖管理有gradle和maven,在这里选择比较常用和方便的Maven作为工程项目和依赖管理工具来搭建SpringCloud实战工程。主要用到的maven管理方式是多模块和bom依赖管理。 什么是maven的多模块依赖管理 Maven 多模块项目相对于单模块项目而言,依赖是…...
uniapp直接连接wifi(含有ios和安卓的注意事项)
前言 小程序中直接连接wifi-----微信小程序 代码 启动 //启动wifistartWifi() {return new Promise((resolve, reject) > {uni.startWifi({success: (res) > {console.log(启动wifi 成功, res)resolve(true)},fail: (err) > {console.error(启动wifi 失败, err)uni.s…...
一. Ubuntu入门
目录 一. Ubuntu系统安装 1. 安装虚拟机软件VMware 2. 安装Ubuntu操作系统 二. Ubuntu系统入门 1. Shell操作 1.1 Shell 简介 1.2 Shell基本操作 1.3 常用Shell命令 (1) 目录信息查看命令ls (2) 目录切换命令cd (3) 当前路径显示命令pwd (4) 系统信息查看命令uname…...
rk3568 Android12 增加支持 ntfs 格式
rk3568 Android12 增加支持 ntfs 格式 Windows平台上可移动硬盘支持 NTFS,FAT32,exFAT三种格式。Fat32文件格式是一种通用格式,任何USB存储设备都会预装该文件系统,可以在任何操作系统平台上使用。最主要的缺陷是只支持最大单文件大小容量为4GB,因此日常使用没有问题,只有…...
【MapReduce】02.Hadoop序列化
实现bean对象序列化步骤 自定义bean对象实现序列化接口。 1)必须实现Writable接口 2)反序列化时,需要反射调用空参构造函数,所以必须有空参构造 public FlowBean(){super(); } 3)重写序列化方法 Override public …...
【Claude 3】一文谈谈Anthropic(Claude) 亚马逊云科技(Bedrock)的因缘际会
文章目录 前言1. Anthropic的诞生2. Anthropic的“代表作”——Claude 3的“三驾马车”3. 亚马逊云科技介绍4. 强大的全托管服务平台——Amazon Bedrock5. 亚马逊云科技(AWS)和Anthropic的联系6. Claude 3模型与Bedrock托管平台的关系7. Clude 3限时体验入口分享【⚠️截止3月1…...
c#开发100问?
什么是C#?C#是由谁开发的?C#与Java之间有哪些相似之处?C#与C有哪些不同之处?C#的主要特性是什么?请解释C#中的类和对象。C#中的命名空间是什么?什么是C#中的属性和字段?请解释C#中的继承和多态性…...
回归预测 | Matlab实现BiTCN-BiGRU-Attention双向时间卷积双向门控循环单元融合注意力机制多变量回归预测
回归预测 | Matlab实现BiTCN-BiGRU-Attention双向时间卷积双向门控循环单元融合注意力机制多变量回归预测 目录 回归预测 | Matlab实现BiTCN-BiGRU-Attention双向时间卷积双向门控循环单元融合注意力机制多变量回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.M…...
SpringCloud微服务-RabbitMQ快速入门
文章目录 RabbitMQ快速入门1、什么是MQ?2、RabbitMQ概述3、RabbitMQ的结构和概念4、常见消息模型5、HelloWorld RabbitMQ快速入门 1、什么是MQ? MQ (MessageQueue),中文是消息队列,字面来看就是存放消息的…...
OpenCV学习笔记(五)——图片的缩放、旋转、平移、裁剪以及翻转操作
目录 图像的缩放 图像的平移 图像的旋转 图像的裁剪 图像的翻转 图像的缩放 OpenCV中使用cv2.resize()函数进行缩放,格式为: resize_imagecv2.resize(image,(new_w,new_h),插值选项) 其中image代表的是需要缩放的对象,(new_w,new_h)表…...
c++ 串口通信库
根据资料整理的串口通信库,封装成为了动态库,使用者只需要调用接口即可 使用实例如下: //接受数据 void CSerialPortCommonLibDemoDlg::OnReceive() { char * str NULL; str new char[256]; _port.readAllData(str); CString s…...
数据结构之单链表及其实现!
目录 编辑 1. 顺序表的问题及思考 2.链表的概念结构和分类 2.1 概念及结构 2.2 分类 3. 单链表的实现 3.1 新节点的创建 3.2 打印单链表 3.3 头插 3.4 头删 3.5 尾插 3.6 尾删 3.7 查找元素X 3.8 在pos位置修改 3.9 在任意位置之前插入 3.10 在任意位置删除…...
Ubuntu 22.04修改静态ip
1. 备份原网络配置文件 # 配置文件名称因机器设置有异 cd /etc/netplan cp 01-network-config.yaml 01-network-config.yaml.bak# 文件内容如下 network:version: 2renderer: NetworkManager2. 修改配置文件 使用 ipconfig 命令查看网络信息,ip addr 命令也可 我这…...
kali当中不同的python版本切换(超简单)
kali当中本身就是自带两个python版本的 配置 update-alternatives --install /usr/bin/python python /usr/bin/python2 100 update-alternatives --install /usr/bin/python python /usr/bin/python3 150 切换版本 update-alternatives --config python 0 1 2编号选择一个即可…...
MongoDB聚合运算符;$dateToString
$dateToString聚合运算符按用户指定的格式将日期对象转为字符串。 语法 { $dateToString: {date: <dateExpression>,format: <formatString>,timezone: <tzExpression>,onNull: <expression> } }字段说明: 字段是否必须描述date是<da…...
【开源】SpringBoot框架开发教学资源共享平台
目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 课程档案模块2.3 课程资源模块2.4 课程作业模块2.5 课程评价模块 三、系统设计3.1 用例设计3.2 类图设计3.3 数据库设计3.3.1 课程档案表3.3.2 课程资源表3.3.3 课程作业表3.3.4 课程评价表 四、系统展…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

