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 课程评价表 四、系统展…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...
小智AI+MCP
什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析:AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github:https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...
大模型——基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程
基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程 下载安装Docker Docker官网:https://www.docker.com/ 自定义Docker安装路径 Docker默认安装在C盘,大小大概2.9G,做这行最忌讳的就是安装软件全装C盘,所以我调整了下安装路径。 新建安装目录:E:\MyS…...

