【Linux】socket编程2

在这里插入图片描述

欢迎来到Cefler的博客😁
🕌博客主页:折纸花满衣
🏠个人专栏:题目解析

在这里插入图片描述


目录

  • 👉🏻客户端代码
    • Makefile(生成目标文件)
    • UdpClient.cc(客户端代码)
    • 服务端代码部分优化1(接受客户端时显示客户端地址信息)
    • InetAddrtoLocal.hpp(将网络地址信息转为主机地址信息)
      • inet_ntoa
    • 服务端代码部分优化2(不给服务器绑定具体IP地址)
    • Udpserver.hpp(去除了ip成员)
    • Main.cc
  • 👉🏻windows充当client给服务端发消息
  • 👉🏻实现处理命令
    • Udpserver.hpp
    • Main.cc
    • popen函数
    • fgets函数

👉🏻客户端代码

Makefile(生成目标文件)

UdpClient.cc(客户端代码)

#include<iostream>
#include"Log.hpp"
#include"ComErr.hpp"
#include<unistd.h>
#include<cstring>//包含strerror函数
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<cerrno>using namespace std;
void Usage(std::string proc)
{std::cout << "Usage : \n\t" << proc << " local_ip local_port\n" << std::endl;
}
int main(int argc,char* argv[3])
{if(argc!=3){Usage(argv[0]);exit(Usage_Err);//unistd.h}//客户端输入的ip地址和端口号,是要发送对象的ip地址和端口号,这里我们从命令行记录一下string ip = argv[1];uint16_t port = stoi(argv[2]);//给client创建套接字对象int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd==-1){lg.LogMessage(Fatal,"socket err : %d %s\n",errno,strerror(errno));//cerrnoexit(Socket_Err);}//client不需要手动绑定唯一网络信息,具体解释后面给出//接下来就是发送消息给服务端并接收服务端消息//但是发送数据前我们需要准备好报头,即目标对象的地址信息struct sockaddr_in dest;memset(&dest,0,sizeof(dest));dest.sin_family = AF_INET;//协议族dest.sin_port = htons(port);//将主机号变为网络序列dest.sin_addr.s_addr = inet_addr(ip.c_str());//ip地址转4字节且是网络序列socklen_t len = sizeof(dest);while(true){//1.发送消息string inbuffer;cout<<"Please enter :";getline(cin,inbuffer);//stringssize_t n = sendto(sockfd,inbuffer.c_str(),inbuffer.size(),0,(struct sockaddr*)&dest,len);if(n!=-1){//发送成功//2.接收服务端消息int defaultbuffer = 1024;char buffer[defaultbuffer];struct sockaddr_in temp;//存储服务端地址信息socklen_t templen = sizeof(temp);ssize_t ret = recvfrom(sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&temp,&templen);if(ret!=0){//接收到服务端消息buffer[ret] = '\0';cout<<"Server say :"<<buffer;}else{cout<<"服务端并未回应...\n";}}else{cout<<"send fail\n";break;}}close(sockfd);return 0;}

至此我们实现了客户端代码,现在让我们将其和服务端进行联动吧😄

在这里插入图片描述
效果还是不错的。

这里要解释几个要点:
🍎1.为什么client不能绑定唯一端口而是随机绑定?
因为会有非常多的客户端,比如我今天打开qq,qq客户端绑定了一个唯一端口号999,然后我又打开了王者荣耀,此时王者荣耀也想绑定999的端口号,此时就会起冲突,导致客户端打开错误了!
所以client需要Bind,但是不需要显示bind,让本地OS自动随机bind,选择随机端口号

什么时候bind? 在client首次发送数据的时候,进行由内核随机Bind

🍎2.ip地址127.0.0.1
IP地址127.0.0.1是IPv4地址中的一个特殊地址,它被保留用于本地环回测试。当你在计算机上访问127.0.0.1时,实际上是在访问你自己的计算机。这个地址通常被用来进行网络客户端/服务器测试,因为它允许在没有真实网络连接的情况下模拟网络通信。

当你将127.0.0.1作为目标IP地址时,你的计算机会尝试与自己进行通信。这对于测试网络应用程序、调试网络问题或者简单地检查网络服务是否正在正常运行非常有用。例如,当你在本地运行一个Web服务器时,可以通过在浏览器中输入"http://127.0.0.1"来访问它,而无需连接到真实的互联网。

服务端代码部分优化1(接受客户端时显示客户端地址信息)

这里我们专门写一个将网络信息转换为主机信息的类

InetAddrtoLocal.hpp(将网络地址信息转为主机地址信息)

#pragma once#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
using namespace std;class InetAddrtoLocal
{
public:InetAddrtoLocal(){}InetAddrtoLocal(struct sockaddr_in& addr):_addr(addr){_port= ntohs(_addr.sin_port);//将16位无符号短整数从网络字节序(大端序)转换为主机字节序。_ip = inet_ntoa(_addr.sin_addr);}string Ip(){return _ip;}uint16_t Port(){return _port;}string Info(){string info = _ip;info+=":";info+=to_string(_port);return info;}
private:string _ip;uint16_t _port;struct sockaddr_in _addr;
};

而后服务端那边部分代码稍微改下就行
服务端部分代码:👇🏻

  if(n!=-1){//说明接受信息成功//接下来我们将打印发送方的信息buffer[n] = '\0';InetAddrtoLocal sender(peer);printf("Client[%s] : %s\n",(sender.Info()).c_str(),buffer);//cout<<"Client say : "<<buffer<<endl;//接下来也发送一些信息回应客户端char retstr[] = "Got it,processing...\n";sendto(_sockfd,retstr,sizeof(retstr),0,(struct sockaddr*)&peer,len);}

效果如下:
在这里插入图片描述

inet_ntoa

inet_ntoa函数是一个C语言中用于将32位IPv4地址转换为点分十进制字符串表示的函数。在头文件<arpa/inet.h>中声明。它接受一个struct in_addr类型的IPv4地址作为参数,并返回一个表示该地址的字符串。

以下是inet_ntoa函数的原型:

char *inet_ntoa(struct in_addr in);

其中in是一个struct in_addr类型的IPv4地址结构体。

inet_ntoa函数将32位的IPv4地址从二进制格式转换为点分十进制格式,并将结果存储在一个静态分配的缓冲区中,然后返回该缓冲区的指针。请注意,由于使用了静态缓冲区,因此每次调用inet_ntoa函数时,都会覆盖上一次调用的结果。因此,如果需要保存多个IPv4地址的字符串表示,应该将结果复制到另一个缓冲区中,以免被覆盖。

以下是一个示例,展示了如何使用inet_ntoa函数将IPv4地址转换为点分十进制字符串:

#include <stdio.h>
#include <arpa/inet.h>int main() {struct in_addr addr;addr.s_addr = inet_addr("192.0.2.1");char *ip_str = inet_ntoa(addr);printf("IPv4 Address: %s\n", ip_str);return 0;
}

在这个示例中,首先将IPv4地址字符串"192.0.2.1"转换为struct in_addr类型的结构体,然后使用inet_ntoa函数将其转换为点分十进制字符串,并最终打印出来。

服务端代码部分优化2(不给服务器绑定具体IP地址)

在网络编程中,通常更推荐将服务器绑定到本地的随机IP地址,而不是固定的IP地址。这种方式通常被称为"本地绑定随机IP"或"通配绑定"。

以下是几个原因:

  1. 灵活性和可移植性: 如果服务器绑定了一个固定的IP地址,那么当需要将服务器迁移到另一个网络环境时,可能需要重新配置服务器以适应新的网络环境。而本地绑定随机IP的方式可以使得服务器更加灵活和可移植,因为它会自动选择可用的本地IP地址进行绑定,无需手动配置

  2. 多网卡支持: 如果服务器有多个网络接口或多个IP地址,本地绑定随机IP的方式可以更好地利用这些资源,使得服务器能够在多个网络接口或多个IP地址上同时监听连接。

  3. 容错性: 本地绑定随机IP的方式可以提高服务器的容错性。当服务器监听的IP地址不可用时(例如,由于网络故障或IP地址冲突),服务器可以尝试绑定到另一个可用的本地IP地址,从而避免服务中断。

  4. 安全性: 通过本地绑定随机IP的方式,可以减少服务器暴露在公共网络上的风险。固定IP地址可能会成为黑客攻击的目标,而使用随机IP地址可以增加攻击者对服务器的识别和定位的难度。

在网络编程中,经常会使用INADDR_ANY来赋值给IP地址。这个常量表示"任意"或"所有"的IP地址,通常用于服务器端绑定监听所有可用的网络接口,而不关心具体是哪个网络接口。具体来说,将IP地址设置为INADDR_ANY可以使服务器监听所有可用的网络接口上的连接请求,而不必关心具体是哪个网卡或IP地址

所以,客户端代码要改的话,就是命令行参数我们不需要指定具体的ip了,而是让内核自定义随机可用的ip地址。

Udpserver.hpp(去除了ip成员)

#include<iostream>
#include "ComErr.hpp"
#include"Log.hpp"
#include <cstring>
#include<sys/types.h>
#include<sys/socket.h>
#include<cerrno>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"InetAddrtoLocal.hpp"using namespace std;const string defaultip = "127.0.0.0";
const uint16_t defaultport = 8888;
class Udpsever
{
public:Udpsever(Udpsever& udp)=delete;//防止拷贝Udpsever(const Udpsever& udp)=delete;const Udpsever& operator=(Udpsever& udp)=delete;Udpsever(const uint16_t& port = defaultport):_port(port){}void Init(){//1.创建套接字对象_sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建一个套接字对象,协议族为IPv4,套接字类型是数据报套接字if(_sockfd<0){//创建失败则打印错误日志lg.LogMessage(Fatal,"socket err,%d : %s\n",errno,strerror(errno));//strerror需要包含头文件cstringexit(Socket_Err);}//成功则打印返回的套接字描述符lg.LogMessage(Info,"sockfd : %d\n",_sockfd);//上述我们只是创建了一个套接字对象,即我们本地的ip和端口号已经有了//但是接下来我们要与网络信息绑定,才能实现在网络中进行通信//我们要用到socket编程中的bind函数:用于将套接字与特定的地址(IP地址和端口号)绑定在一起,以便其他计算机可以找到并与之通信//2.bind并指定网络信息//2.1指定网络地址信息struct sockaddr_in local;//创建一个网络地址信息结构体,接下里初始化地址信息bzero(&local,sizeof(local));//相当于memsetlocal.sin_family = AF_INET;//1.初始化协议族local.sin_port = htons(_port);//2.将16位无符号短整数从主机字节序转换为网络字节序(大端序)local.sin_addr.s_addr = INADDR_ANY;//3.初始化ip地址,这里我们想让_ip变为4字节且是网络字节序,所以使用转换函数inet_addr//2.2将网络地址信息与socket文件对象进行绑定//bind函数原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);int bd = bind(_sockfd,(const struct sockaddr *)&local,sizeof(local));if(bd!=0){lg.LogMessage(Fatal,"bind err :%d %s\n",errno,strerror(errno));exit(Bind_Err);}//至此socket初始化完成}void Start(){int defaultbuffer = 1024;char buffer[defaultbuffer];while(true)//服务器永远不退出{//接受信息struct sockaddr_in peer;//用来存储发送方的地址信息socklen_t len = sizeof(peer);ssize_t n = recvfrom(_sockfd,buffer,sizeof(buffer)-1/*再减1是给\0留位置*/,0,(struct sockaddr*)&peer,&len);if(n!=-1){//说明接受信息成功//接下来我们将打印发送方的信息buffer[n] = '\0';InetAddrtoLocal sender(peer);printf("Client[%s] : %s\n",(sender.Info()).c_str(),buffer);//cout<<"Client say : "<<buffer<<endl;//接下来也发送一些信息回应客户端char retstr[] = "Got it,processing...\n";sendto(_sockfd,retstr,sizeof(retstr),0,(struct sockaddr*)&peer,len);}}}
private:uint16_t _port;//端口号int _sockfd;//套接字描述符
};

Main.cc

#include "Udpserver.hpp"
#include "ComErr.hpp"
#include <memory>void Usage(std::string proc)
{std::cout << "Usage : \n\t" << proc << "local_port\n" << std::endl;
}
int main(int argc,char* argv[2])
{if(argc!=2)//如果命令行指令数没有两个{Usage(argv[0]);return Usage_Err;}//string ip = argv[1];//获取ipuint16_t port = stoi(argv[1]);//获取端口号//接下来创建Udpserver的指针unique_ptr<Udpsever> usvr = std::make_unique<Udpsever>(port);//unique_ptr不支持拷贝构造和赋值操作,因此确保了资源的独占性//使用make_unique记得添加memory头文件usvr->Init();usvr->Start();return 0;
}

效果如下: 👇🏻
在这里插入图片描述

👉🏻windows充当client给服务端发消息

#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <string>#pragma comment(lib,"ws2_32.lib")//引入动态库 using namespace std;uint16_t serverport = 8081;
string serverip = "110.40.135.148";int main()
{WSADATA wsd;if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)//给动态库初始化 {cout << "WSAStartup failed\n";return 1;}SOCKET sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd == INVALID_SOCKET){cout << "socket create failed\n";WSACleanup();return 1;}struct sockaddr_in dest;memset(&dest, 0, sizeof(dest));dest.sin_family = AF_INET;dest.sin_port = htons(serverport);dest.sin_addr.s_addr = inet_addr(serverip.c_str());int len = sizeof(dest);while (true){string inbuffer;cout << "Please enter :";getline(cin, inbuffer);int n = sendto(sockfd, inbuffer.c_str(), inbuffer.size(), 0, (struct sockaddr*)&dest, len);if (n != SOCKET_ERROR){cout << "send success" << endl;const int defaultbuffer = 1024;char buffer[defaultbuffer];struct sockaddr_in temp;int templen = sizeof(temp);int ret = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&temp, &templen);if (ret != SOCKET_ERROR){buffer[ret] = '\0';cout << "Server say: " << buffer << endl;}else{cout << "recvfrom failed: " << WSAGetLastError() << endl;}}else{cout << "sendto failed: " << WSAGetLastError() << endl;}// Add a condition to exit the loopif (inbuffer == "exit"){break;}}closesocket(sockfd);WSACleanup();//清理ws2库 return 0;
}

经过我的测试
说实话代码没有问题,数据也能发送成功。
但是不知道是不是因为网络防火墙的原因,服务端那边一直阻塞在recvfrom函数那里,导致数据一直不能被读出,也是很尴尬了(后续我再看看有没有什么办法)

👉🏻实现处理命令

这里我只给出修改过代码的源文件

Udpserver.hpp

#include<iostream>
#include "ComErr.hpp"
#include"Log.hpp"
#include <cstring>
#include<sys/types.h>
#include<sys/socket.h>
#include<cerrno>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"InetAddrtoLocal.hpp"#include<functional>
using namespace std;const string defaultip = "127.0.0.0";
const uint16_t defaultport = 8888;
const int defaultbuffer = 1024;using func_t = function<string(string)>;//定义函数类型class Udpsever
{
public:Udpsever(Udpsever& udp)=delete;//防止拷贝Udpsever(const Udpsever& udp)=delete;const Udpsever& operator=(Udpsever& udp)=delete;Udpsever(func_t OnMessage,const uint16_t& port = defaultport):_port(port),_OnMessage(OnMessage){}void Init(){//1.创建套接字对象_sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建一个套接字对象,协议族为IPv4,套接字类型是数据报套接字if(_sockfd<0){//创建失败则打印错误日志lg.LogMessage(Fatal,"socket err,%d : %s\n",errno,strerror(errno));//strerror需要包含头文件cstringexit(Socket_Err);}//成功则打印返回的套接字描述符lg.LogMessage(Info,"sockfd : %d\n",_sockfd);//上述我们只是创建了一个套接字对象,即我们本地的ip和端口号已经有了//但是接下来我们要与网络信息绑定,才能实现在网络中进行通信//我们要用到socket编程中的bind函数:用于将套接字与特定的地址(IP地址和端口号)绑定在一起,以便其他计算机可以找到并与之通信//2.bind并指定网络信息//2.1指定网络地址信息struct sockaddr_in local;//创建一个网络地址信息结构体,接下里初始化地址信息bzero(&local,sizeof(local));//相当于memsetlocal.sin_family = AF_INET;//1.初始化协议族local.sin_port = htons(_port);//2.将16位无符号短整数从主机字节序转换为网络字节序(大端序)local.sin_addr.s_addr = INADDR_ANY;//3.初始化ip地址,这里我们想让_ip变为4字节且是网络字节序,所以使用转换函数inet_addr//2.2将网络地址信息与socket文件对象进行绑定//bind函数原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);int bd = bind(_sockfd,(const struct sockaddr *)&local,sizeof(local));if(bd!=0){lg.LogMessage(Fatal,"bind err :%d %s\n",errno,strerror(errno));exit(Bind_Err);}//至此socket初始化完成}void Start(){cout<<"start"<<endl;char buffer[defaultbuffer];while(true)//服务器永远不退出{cout<<"running..."<<endl;//接受信息struct sockaddr_in peer;//用来存储发送方的地址信息socklen_t len = sizeof(peer);ssize_t n = recvfrom(_sockfd,buffer,sizeof(buffer)-1/*再减1是给\0留位置*/,0,(struct sockaddr*)&peer,&len);if(n!=-1){cout<<"收到\n";//说明接受信息成功//接下来我们将打印发送方的信息buffer[n] = '\0';//处理消息string response = _OnMessage(buffer);// InetAddrtoLocal sender(peer);// printf("Client[%s] : %s\n",(sender.Info()).c_str(),buffer);// //cout<<"Client say : "<<buffer<<endl;// //接下来也发送一些信息回应客户端// char retstr[] = "Got it,processing...\n";sendto(_sockfd,response.c_str(),response.size(),0,(struct sockaddr*)&peer,len);}else{cout<<"没收到\n";strerror(errno);}}}
private:uint16_t _port;//端口号int _sockfd;//套接字描述符func_t _OnMessage;//回调函数
};

Main.cc

#include "Udpserver.hpp"
#include "ComErr.hpp"
#include <memory>
#include<cstdio>
#include<vector>void Usage(std::string proc)
{std::cout << "Usage : \n\t" << proc << "local_port\n" << std::endl;
}string OnMessageDefault(string request)
{return request + "[got message]\n";
}std::vector<std::string> black_words = {//黑名单"rm","unlink","cp","mv","chmod","exit","reboot","halt","shutdown","top","kill","dd","vim","vi","nano","man"
};
bool SafeCheck(std::string command)
{for(auto &k : black_words){std::size_t pos = command.find(k);if(pos != std::string::npos) return false;}return true;
}
string ExcuteCommand(string command)
{if(!SafeCheck(command)) return "bad man!!\n";cout<<"get a message: "<< command<<endl;FILE* fp = popen(command.c_str(),"r");if(fp == nullptr){return "excute error,reason is unknown\n";}string response;char buffer[1024];while(true){char* s = fgets(buffer,sizeof(buffer),fp);if(!s) break;else response+=buffer;}pclose(fp);return response.empty()?"Nothing excute\n":response;//将处理结果输出到屏幕上
}
int main(int argc,char* argv[2])
{if(argc!=2)//如果命令行指令数没有三个{Usage(argv[0]);return Usage_Err;}//string ip = argv[1];//获取ipuint16_t port = stoi(argv[1]);//获取端口号//接下来创建Udpserver的指针unique_ptr<Udpsever> usvr = std::make_unique<Udpsever>(ExcuteCommand,port);//unique_ptr不支持拷贝构造和赋值操作,因此确保了资源的独占性//使用make_unique记得添加memory头文件usvr->Init();usvr->Start();return 0;
}

popen函数

popen 函数是一个 C 标准库中的函数,用于创建一个进程,并建立一个管道连接到该进程的标准输入或标准输出。它通常用于创建子进程,并与其进行双向通信。

popen 函数的原型如下:

FILE *popen(const char *command, const char *mode);

其中,command 参数是一个字符串,表示要执行的命令,mode 参数是一个字符串,指定打开的管道是用于读取还是写入。mode 参数可以是 "r"(读取)或 "w"(写入)。

popen 函数返回一个 FILE 指针,可以像使用 fopen 返回的文件指针一样来操作管道。如果 popen 调用失败,它将返回 NULL

下面是一个简单的示例,演示如何使用 popen 函数来执行一个命令并读取其输出:

#include <stdio.h>int main() {FILE *pipe;char buffer[128];// 执行命令并读取其输出pipe = popen("ls -l", "r");if (pipe == NULL) {perror("popen");return -1;}// 读取管道的输出并打印到标准输出while (fgets(buffer, sizeof(buffer), pipe) != NULL) {printf("%s", buffer);}// 关闭管道pclose(pipe);return 0;
}

在这个示例中,我们使用 popen 执行了 ls -l 命令,并从其输出中读取文件列表,并将其打印到标准输出。最后,使用 pclose 函数关闭了管道。

需要注意的是,popen 函数在 Windows 平台上不是标准 C 库的一部分,并且可能不可用。在 Windows 上,可以考虑使用 _popen_pclose 函数来实现类似的功能。

fgets函数

fgets 函数是 C 标准库中用于从文件流中读取一行数据的函数。它的原型如下:

char *fgets(char *str, int n, FILE *stream);

其中:

  • str 是一个指向字符数组的指针,用于存储读取的字符串。
  • n 是一个整数,表示要读取的最大字符数,包括最后的空字符 ‘\0’。
  • stream 是一个指向文件的指针,指定要读取的文件流。

fgets 函数会从指定的文件流中读取字符,直到遇到换行符 ‘\n’、文件结束符 EOF 或者读取了 n-1 个字符为止(包括换行符)。它会将读取的字符存储到 str 指向的字符数组中,并在末尾添加一个空字符 ‘\0’,以表示字符串的结束。

fgets 函数的返回值是一个指向目标字符数组的指针,即参数 str 的值,或者在发生错误或到达文件末尾时返回 NULL

下面是一个简单的示例,演示如何使用 fgets 函数从文件中读取一行数据:

#include <stdio.h>int main() {FILE *file;char buffer[128];// 打开文件以供读取file = fopen("example.txt", "r");if (file == NULL) {perror("fopen");return -1;}// 从文件中读取一行数据while (fgets(buffer, sizeof(buffer), file) != NULL) {printf("%s", buffer);}// 关闭文件fclose(file);return 0;
}

在这个示例中,我们打开一个名为 example.txt 的文件以供读取,然后使用 fgets 函数从文件中逐行读取数据,并将其打印到标准输出。最后,使用 fclose 函数关闭文件。


如上便是本期的所有内容了,如果喜欢并觉得有帮助的话,希望可以博个点赞+收藏+关注🌹🌹🌹❤️ 🧡 💛,学海无涯苦作舟,愿与君一起共勉成长

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/804807.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ffmpeg 将多个视频片段合成一个视频

ffmpeg 将多个视频片段合成一个视频 References 网络视频 6 分钟的诅咒。 新建文本文件 filelist.txt filelist.txtfile output_train_video_0.mp4 file output_train_video_1.mp4 file output_train_video_2.mp4 file output_train_video_3.mp4 file output_train_video_4.m…

淘宝扭蛋机小程序源码搭建:打造专属电商娱乐新平台

在数字化浪潮的推动下&#xff0c;电商平台不断创新&#xff0c;以满足消费者日益多样化的需求。淘宝扭蛋机小程序作为一种创新的电商娱乐形式&#xff0c;受到了广大用户的热烈追捧。为了满足市场需求&#xff0c;许多企业和开发者开始关注淘宝扭蛋机小程序的源码搭建&#xf…

Spring6-单元测试:JUnit

1. 概念 在进行单元测试时&#xff0c;特别是针对使用了Spring框架的应用程序&#xff0c;我们通常需要与Spring容器交互以获取被测试对象及其依赖。传统做法是在每个测试方法中手动创建Spring容器并从中获取所需的Bean。以下面的两行常见代码为例&#xff1a; ApplicationCo…

[C语言][数据结构][链表] 单链表的从零实现!

目录 零.必备知识 1.一级指针 && 二级指针 2. 节点的成员列表 a.数据 b.指向下一个节点的指针. 3. 动态内存空间的开辟 (malloc-calloc-realloc) 一.单链表的实现与销毁 1.1 节点的定义 1.2 单链表的尾插 1.3 单链表的头插 1.4 单链表的尾删 1.5 单链表的头删 1…

挑错罐头=“害猫”!猫咪主食罐到底应该怎么选?

猫咪罐头已经成为众多猫奴们的喂养首选。它富含水分&#xff0c;有助于猫咪保持良好的泌尿系统健康&#xff0c;尤其对于那些不太喜欢饮水的猫咪来说&#xff0c;罐头无疑是补充水分的理想方式。罐头的口感极佳&#xff0c;肉质细腻&#xff0c;能够激发猫咪的食欲&#xff0c;…

C语言—每日选择题—Day65

前言 我们的刷题专栏又又又开始了&#xff0c;本专栏总结了作者做题过程中的好题和易错题。每道题都会有相应解析和配图&#xff0c;一方面可以使作者加深理解&#xff0c;一方面可以给大家提供思路&#xff0c;希望大家多多支持哦&#xff5e; 第一题 1、如下代码输出的是什么…

深入理解LRU缓存算法:原理、应用与优化

LRU算法&#xff08;Least Recently Used&#xff0c;最近最少使用算法&#xff09;的思想是基于"时间局部性"原理&#xff0c;即在一段时间内&#xff0c;被访问过的数据在未来仍然会被频繁访问的概率较高。 LRU 原理 LRU算法的主要思想是将最近被使用的数据保留在…

UEditor编辑器自动将div标签转换成p标签应该如何解决 ———————————————— 版权声明:本文为博主原创文章,遵循 CC 4

首先在ueditor的文件夹下找到ueditor.all.js文件&#xff0c;然后搜索allowDivTransToP找到这段代码&#xff0c;把后面的true设置为false 接着在ueditor.config.js文件内搜索allowDivTransToP找到如下的代码&#xff0c;将注释去掉并且改为false //默认过滤规则相关配置项目/…

MPT - 原理及应用

前文回顾 Merkle原理及应用Merkle代码实现Patricia原理及应用Patricia代码实现 什么是MPT&#xff08;Merkle Patricia Tree&#xff09;树 MPT树是一种数据结构&#xff0c;用于在以太坊区块链中高效地存储和检索账户状态、交易历史和其他重要数据。MPT树的设计旨在结合Merk…

sqlmap(四)案例

一、注入DB2 http://124.70.71.251:49431/new_list.php?id1 这是墨者学院里的靶机&#xff0c;地址&#xff1a;https://www.mozhe.cn/ 1.1 测试数据库类型 python sqlmap.py -u "http://124.70.71.251:49431/new_list.php?id1" 1.2 测试用户权限类型 查询选…

常见深度学习之十二大激活函数【函数定义、性质、数学公式、代码实现】

目录 前言 1、激活函数的定义与作用 2、激活函数的性质 二、常见的激活函数 2.1 Sigmoid函数&#xff1a; 1. 作用 2. 优点 3. 缺点 4. 数学公式 5.Sigmoid函数实现及可视化图像 2.2 Tanh函数 1. 函数定义 2.优点 3.缺点 4.Tanh函数实现及可视化图像 2.3ReLU 函数 &#xff1a;…

物联网实战--驱动篇之(二)Modbus协议

目录 一、modbus简介 二、功能码01、02 三、modbus解析 四、功能码03、04 五、功能码05 六、功能码06 七、功能码16 一、modbus简介 我们在网上查阅modbus的资料发现很多很杂&#xff0c;modbus-RTU ASCII TCP等等&#xff0c;还有跟PLC结合的&#xff0c;地址还分1开…

C语言进阶课程学习记录-第29课 - 指针和数组分析(下)

C语言进阶课程学习记录-第29课 - 指针和数组分析&#xff08;下&#xff09; 数组名与指针实验-数组形式转换实验-数组名与指针的差异实验-转化后数组名加一的比较实验-数组名作为函数形参小结 本文学习自狄泰软件学院 唐佐林老师的 C语言进阶课程&#xff0c;图片全部来源于课…

【JavaWeb】Day39.MySQL概述——数据库设计-DQL(二)

数据库设计-DQL 聚合函数 聚合函数查询就是纵向查询&#xff0c;它是对一列的值进行计算&#xff0c;然后返回一个结果值。&#xff08;将一列数据作为一个整体&#xff0c;进行纵向计算&#xff09; 语法&#xff1a; select 聚合函数(字段列表) from 表名 ; 注意 : 聚合…

软件设计—接口安全设计规范

1.token授权机制 2.https传输加密 3.接口调用防滥用 4.日志审计里监控 5.开发测试环境隔离&#xff0c;脱敏处理 6.数据库运维监控审计 软件项目相关全套精华资料包获取方式①&#xff1a;点我获取 获取方式②&#xff1a;本文末个人名片直接获取。

高校人事管理系统业务分析

目标用户 大学人事部门&#xff0c;部门、院系、任务 解决问题 人事部门按业务划分了很多科室、数据分散、工作流程杂乱、工作效率低。 主要功能模块 人事综合管理平台、个人自助服务平台、人才招聘管理系统、薪酬管理子系统、职称评审子系统、绩效考核子系统组成。

泛零售行业大会员经营的业务挑战与应对策略

​泛零售企业发展到成规模阶段一定会沉淀大量会员&#xff0c;在当前的市场竞争下&#xff0c;企业的经营重点在关注增量市场的同时&#xff0c;也会聚焦对存量会员的价值深挖&#xff0c;提升会员忠诚度&#xff0c;实现“以客户体验为中心、以数据驱动运营”。 对于多业态、…

小程序打开空白的问题处理

小程序打开是空白的&#xff0c;如下&#xff1a; 这个问题都是请求域名的问题&#xff1a; 一、检查服务器域名配置了 https没有&#xff0c;如果没有&#xff0c;解决办法是申请个ssl证书&#xff0c;具体看这里 https://doc.crmeb.com/mer/mer2/4257 二、完成第一步后&#…

基于springboot实现墙绘产品展示交易平台管理系统项目【项目源码+论文说明】

基于springboot实现墙绘产品展示交易平台系统演示 摘要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本墙绘产品展示交易平台就是在这样的大环境下诞生&#xff…

RTSP/Onvif视频安防监控平台EasyNVR调用接口返回匿名用户名和密码的原因排查

视频安防监控平台EasyNVR可支持设备通过RTSP/Onvif协议接入&#xff0c;并能对接入的视频流进行处理与多端分发&#xff0c;包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等多种格式。平台拓展性强、支持二次开发与集成&#xff0c;可应用在景区、校园、水利、社区、工地等场…