VS2022配置WinPcap开发

news2025/1/12 2:42:12

winpcap 官网:http://www.winpcap.org/
1.首先下载安装 winpcap.exe,http://www.winpcap.org/install/default.htm
目的是安装相关驱动和 dll,安装完成之后基于 winpcap 的应用程序才能够正常运行。
2.下载 winpcap 的开发包,头文件和库文件:http://www.winpcap.org/devel.htm,解压之后主要是头文件和库文件,记得将 WpdPack 复制到 D 盘(直接放在D盘,不要包含在其他文件夹下),如图所示:

VS2022新建一个C++工程,具体操作可参考我上一篇文章,文章链接如下:http://t.csdnimg.cn/RRO57

创建工程后,首先在 vs 中配置(vc++目录:include 目录和 lib 目录),具体步骤如下:

点击“项目”,再点击最下方的属性:

点击VC++目录,如图所示:

接下来修改“包含目录”和“库目录”,包含目录修改为:D:\WpdPack\Include;$(IncludePath)

库目录修改为:D:\WpdPack\Lib\x64;$(LibraryPath),如图所示:

接着,link 输入:wpcap.lib,ws2_32.lib,具体步骤如下:

在左边的配置属性找到“链接器”,点击,接着点击“输入”:

然后在“附加依赖项”处,添加wpcap.lib和ws2_32.lib两个库,如图所示:(前面的用这两个替换掉,后面的不要动)

接着点击配置预处理器定义,具体步骤如下:

在配置属性处点击C/C++,接着点击“预处理器”,如图所示:

在“预处理器定义”处修改为“WPCAP;HAVE_REMOTE;WIN32;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS”,如图所示:

接着点击“应用”,再点击“确定”,如图:

代码如下:

//#define HAVE_REMOTE
//#define WPCAP
#include "pcap.h" 
#include <winsock2.h>
#include <string.h>
#include <stdio.h>
using namespace std;
#pragma comment(lib, "wpcap.lib")
#pragma comment(lib, "Ws2_32.lib")
#define LINE_LEN 16
#define MAX_ADDR_LEN 16
FILE* file = 0;
int ip_len;
int tcp_len;
// 以太网协议格式的定义
typedef struct ether_header {
	u_char ether_dhost[6]; // 目标 MAC 地址
	u_char ether_shost[6]; // 源 MAC 地址
	u_short ether_type; // 以太网类型
}ether_header;
// 用户保存 4 字节的 IP 地址
typedef struct ip_address {
	u_char byte1;
	u_char byte2;
	u_char byte3;
	u_char byte4;
}ip_address;
// 用于保存 IPV4 的首部
typedef struct ip_header {
	u_char version_hlen; // 首部长度 版本
	u_char tos; // 服务质量
	u_short tlen; // 总长度
	u_short identification; // 身份识别
	u_short flags_offset; // 标识 分组偏移
	u_char ttl; // 生命周期
	u_char proto; // 协议类型
	u_short checksum; // 包头测验码
	u_int saddr; // 源 IP 地址
	u_int daddr; // 目的 IP 地址
}ip_header;
// 用于保存 TCP 首部
typedef struct tcp_header {
	u_short sport;
	u_short dport;
	u_int sequence; // 序列码
	u_int ack; // 回复码
	u_char hdrLen; // 首部长度保留字
	u_char flags; // 标志
	u_short windows; // 窗口大小
	u_short checksum; // 校验和
	u_short urgent_pointer; // 紧急指针
}tcp_header;
// 用于保存 UDP 的首部
typedef struct udp_header {
	u_short sport; // 源端口
	u_short dport; // 目标端口
	u_short datalen; // UDP 数据长度
	u_short checksum; // 校验和
}udp_header;
// 用于保存 ICMP 的首部
typedef struct icmp_header {
	u_char type; // ICMP 类型
	u_char code; // 代码
	u_short checksum; // 校验和
	u_short identification; // 标识
	u_short sequence; // 序列号
	u_long timestamp; // 时间戳
}icmp_header;
// 用于保存 ARP 的首部
typedef struct arp_header {
	u_short hardware_type; // 格式化的硬件地址
	u_short protocol_type; // 协议地址格式
	u_char hardware_length; // 硬件地址长度
	u_char protocol_length; // 协议地址长度
	u_short operation_code; // 操作码
	u_char source_ethernet_address[6]; // 发送者硬件地址
	u_char source_ip_address[4]; // 发送者协议地址
	u_char destination_ethernet_address[6]; // 目的方硬件地址
	u_char destination_ip_address[4]; // 目的方协议地址
}arp_header;
#define str4cmp(m, c0, c1, c2, c3) \
(m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3)
void http_protocol_packet_handle(u_char* arg, const struct pcap_pkthdr* pkt_header, const
	u_char* pkt_content)
{
	FILE* file1 = 0;
	//下面这个打开文件能写在这里吗?在这里打开有什么问题?写在这里合适吗?如何改进一下?
		if ((file1 = freopen("http.txt", "a", stdout)) == 0)
			printf("Cannot open the file.\n");
	//加上前面的 IP 头以及以太网还有 TCP 头才是 HTTP 数据包头部
	const u_char* http_head = (u_char*)pkt_content + (14 + ip_len + tcp_len);
	if (http_head != NULL) {//报文有内容:
		if (str4cmp(http_head, 'G', 'E', 'T', ' ')) {//判断是否为 GET 请求
			printf("\n===================HTTP Protocol=================\n");
			u_char* uri_start = (u_char*)http_head + 4;
			u_char* p = uri_start;
			printf("当前 HTTP 请求 uri 是:");
			while (true)
			{
				if (str4cmp(p, 'H', 'T', 'T', 'P')) //说明相对 url 读取完毕
					break;
				printf("%c", p[0]);
				p = p + 1;
			}
			printf("\nhost:");
			while (true)
			{
				if (str4cmp(p, 'H', 'o', 's', 't'))
				{
					p = p + 5;//跳过 HOST:
					while (true)
					{
						printf("%c", p[0]);
						if (p[1] == '\n') //如果下一个是换行符,就说明这一行读取结束,host 读取完毕
							break;
						p = p + 1;
					}
					break;
				}
				p = p + 1;
			}
		}
	}
	fclose(stdin);
	fclose(file1);
}
// TCP 协议处理
//u_short sport;
//u_short dport;
//u_int sequence; // 序列码
//u_int ack; // 回复码
//u_char hdrLen; // 首部长度保留字
//u_char flags; // 标志
//u_short windows; // 窗口大小
//u_short checksum; // 校验和
//u_short urgent_pointer; // 紧急指针
// ntohs()是一个函数名,作用是将一个 16 位数由网络字节顺序转换为主机字节顺序
void tcp_protocol_packet_handle(u_char* arg, const struct pcap_pkthdr* pkt_header, const
	u_char* pkt_content)
{
	tcp_header* tcp_protocol;
	tcp_protocol = (tcp_header*)(pkt_content + 14 + 20);
	//cout << sizeof(u_int) << endl;
	printf("===================TCP Protocol=================\n");
	printf("Source Port: %i\n", ntohs(tcp_protocol->sport));
	printf("Destination Port: %i\n", ntohs(tcp_protocol->dport));//8002
	printf("Sequence number: %d\n", ntohl(tcp_protocol->sequence));
	printf("Acknowledgment number: %d\n", ntohl(tcp_protocol->ack));
	printf("Header Length: %d\n", (tcp_protocol->hdrLen >> 4) * 4);
	printf("Flags: 0x%.3x ", tcp_protocol->flags);
	tcp_len = (tcp_protocol->hdrLen >> 4) * 4;
	if (tcp_protocol->flags & 0x08) printf("(PSH)");
	if (tcp_protocol->flags & 0x10) printf("(ACK)");
	if (tcp_protocol->flags & 0x02) printf("(SYN)");
	if (tcp_protocol->flags & 0x20) printf("(URG)");
	if (tcp_protocol->flags & 0x01) printf("(FIN)");
	if (tcp_protocol->flags & 0x04) printf("(RST)");
	if (ntohs(tcp_protocol->dport) == 80)
	{
		//获取 HTTP 数据包的 header 地址 传入 HTTP 解析函数
		http_protocol_packet_handle(arg, pkt_header, pkt_content);
	}
	printf("\n");
	printf("Windows Size: %i\n", ntohs(tcp_protocol->windows));
	printf("Checksum: 0x%.4x\n", ntohs(tcp_protocol->checksum));
	printf("Urgent Pointer: %i\n", ntohs(tcp_protocol->urgent_pointer));
}
// UDP 协议处理
//u_short sport; // 源端口
//u_short dport; // 目标端口
//u_short datalen; // UDP 数据长度
//u_short checksum; // 校验和
void udp_protocol_packet_handle(u_char* arg, const struct pcap_pkthdr* pkt_header, const
	u_char* pkt_content)
{
	udp_header* udp_protocol;
	udp_protocol = (udp_header*)(pkt_content + 14 + 20);
	printf("===================UDP Protocol=================\n");
	printf("Source Port: %i\n", ntohs(udp_protocol->sport));
	printf("Destination Port: %i\n", ntohs(udp_protocol->dport));
	printf("Datalen: %i\n", ntohs(udp_protocol->datalen));
	printf("Checksum: 0x%.4x\n", ntohs(udp_protocol->checksum));
}
// ICMP 协议处理
//u_char type; // ICMP 类型
//u_char code; // 代码
//u_short checksum; // 校验和
//u_short identification; // 标识
//u_short sequence; // 序列号
//u_long timestamp; // 时间戳
void icmp_protocol_packet_handle(u_char* arg, const struct pcap_pkthdr* pkt_header, const
	u_char* pkt_content)
{
	icmp_header* icmp_protocol;
	icmp_protocol = (icmp_header*)(pkt_content + 14 + 20);
	printf("==================ICMP Protocol=================\n");
	printf("Type: %d ", icmp_protocol->type);
	switch (icmp_protocol->type)
	{
	case 8:
		printf("(request)\n");
		break;
	case 0:
		printf("(reply)\n");
		break;
	default:
		printf("\n");
		break;
	}
	printf("Code: %d\n", icmp_protocol->code);
	printf("CheckSum: 0x%.4x\n", ntohs(icmp_protocol->checksum));
	printf("Identification: 0x%.4x\n", ntohs(icmp_protocol->identification));
	printf("Sequence: 0x%.4x\n", ntohs(icmp_protocol->sequence));
}
// ARP 协议处理
//u_short hardware_type; // 格式化的硬件地址
//u_short protocol_type; // 协议地址格式
//u_char hardware_length; // 硬件地址长度
//u_char protocol_length; // 协议地址长度
//u_short operation_code; // 操作码
//u_char source_ethernet_address[6]; // 发送者硬件地址
//u_char source_ip_address[4]; // 发送者协议地址
//u_char destination_ethernet_address[6]; // 目的方硬件地址
//u_char destination_ip_address[4]; // 目的方协议地址
void arp_protocol_packet_handle(u_char* arg, const struct pcap_pkthdr* pkt_header, const
	u_char* pkt_content)
{
	arp_header* arp_protocol;
	arp_protocol = (arp_header*)(pkt_content + 14);
	printf("==================ARP Protocol==================\n");
	printf("Hardware Type: ");
	switch (ntohs(arp_protocol->hardware_type))
	{
	case 1:
		printf("Ethernet");
		break;
	default:
		break;
	}
	printf(" (%d)\n", ntohs(arp_protocol->hardware_type));
	printf("Protocol Type: \n");
	switch (ntohs(arp_protocol->protocol_type))
	{
	case 0x0800:
		printf("%s", "IP");
		break;
	case 0x0806:
		printf("%s", "ARP");
		break;
	case 0x0835:
		printf("%s", "RARP");
		break;
	default:
		printf("%s", "Unknown Protocol");
		break;
	}
	printf(" (0x%04x)\n", ntohs(arp_protocol->protocol_type));
	printf("Hardware Length: %d\n", arp_protocol->hardware_length);
	printf("Protocol Length: %d\n", arp_protocol->protocol_length);
	printf("Operation Code: ");
	switch (ntohs(arp_protocol->operation_code))
	{
	case 1:
		printf("request");
		break;
	case 2:
		printf("reply");
		break;
	default:
		break;
	}
	printf(" (%i)\n", ntohs(arp_protocol->operation_code));
}
// IP 协议处理
//u_char version_hlen; // 首部长度 版本
//u_char tos; // 服务质量
//u_short tlen; // 总长度
//u_short identification; // 身份识别
//u_short flags_offset; // 标识 分组偏移
//u_char ttl; // 生命周期
//u_char proto; // 协议类型
//u_short checksum; // 包头测验码
//u_int saddr; // 源 IP 地址
//u_int daddr; // 目的 IP 地址
void ip_protocol_packet_handle(u_char* arg, const struct pcap_pkthdr* pkt_header, const
	u_char* pkt_content)
{
	ip_header* ip_protocol;
	sockaddr_in source, dest;
	char sourceIP[MAX_ADDR_LEN], destIP[MAX_ADDR_LEN];
	ip_protocol = (ip_header*)(pkt_content + 14);
	source.sin_addr.s_addr = ip_protocol->saddr;
	dest.sin_addr.s_addr = ip_protocol->daddr;
	strncpy(sourceIP, inet_ntoa(source.sin_addr), MAX_ADDR_LEN);
	strncpy(destIP, inet_ntoa(dest.sin_addr), MAX_ADDR_LEN);
	printf("===================IP Protocol==================\n");
	printf("Version: %d\n", ip_protocol->version_hlen >> 4);
	printf("Header Length: %d bytes\n", (ip_protocol->version_hlen & 0x0f) * 4);
	ip_len = (ip_protocol->version_hlen & 0x0f) * 4;
	printf("Tos: %d\n", ip_protocol->tos);
	printf("Total Length: %d\n", ntohs(ip_protocol->tlen));
	printf("Identification: 0x%.4x (%i)\n", ntohs(ip_protocol->identification), ntohs(ip_protocol->identification));
	printf("Flags: %d\n", ntohs(ip_protocol->flags_offset) >> 13);
	printf("---Reserved bit: %d\n", (ntohs(ip_protocol->flags_offset) & 0x8000) >> 15);
	printf("---Don't fragment: %d\n", (ntohs(ip_protocol->flags_offset) & 0x4000) >> 14);
	printf("---More fragment: %d\n", (ntohs(ip_protocol->flags_offset) & 0x2000) >> 13);
	printf("Fragment offset: %d\n", ntohs(ip_protocol->flags_offset) & 0x1fff);
	printf("Time to live: %d\n", ip_protocol->ttl);
	printf("Protocol Type: ");
	switch (ip_protocol->proto)
	{
	case 1:
		printf("ICMP");
		break;
	case 6:
		printf("TCP");
		break;
	case 17:
		printf("UDP");
		break;
	default:
		break;
	}
	printf(" (%d)\n", ip_protocol->proto);
	printf("Header checkSum: 0x%.4x\n", ntohs(ip_protocol->checksum));
	printf("Source: %s\n", sourceIP);
	printf("Destination: %s\n", destIP);
	if (ip_protocol->proto == htons(0x0600))
		tcp_protocol_packet_handle(arg, pkt_header, pkt_content);
	else if (ip_protocol->proto == htons(0x1100))
		udp_protocol_packet_handle(arg, pkt_header, pkt_content);
	else if (ip_protocol->proto == htons(0x0100))
		icmp_protocol_packet_handle(arg, pkt_header, pkt_content);
}
// Ethernet 协议处理
void ethernet_protocol_packet_handle(u_char* arg, const struct pcap_pkthdr* pkt_header, const u_char* pkt_content)
{
	ether_header* ethernet_protocol;//以太网协议
	u_short ethernet_type; //以太网类型
	u_char* mac_string; //以太网地址
	//获取以太网数据内容
	ethernet_protocol = (ether_header*)pkt_content;
	ethernet_type = ntohs(ethernet_protocol->ether_type);
	printf("==============Ethernet Protocol=================\n");
	//以太网目标地址
	mac_string = ethernet_protocol->ether_dhost;
	printf("Destination Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string,
		*(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
	//以太网源地址
	mac_string = ethernet_protocol->ether_shost;
	printf("Source Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
	printf("Ethernet type: ");
	switch (ethernet_type)
	{
	case 0x0800:
		printf("%s", "IP");
		break;
	case 0x0806:
		printf("%s", "ARP");
		break;
	case 0x0835:
		printf("%s", "RARP");
		break;
	default:
		printf("%s", "Unknown Protocol");
		break;
	}
	printf(" (0x%04x)\n", ethernet_type);
	switch (ethernet_type)
	{
	case 0x0800:
		ip_protocol_packet_handle(arg, pkt_header, pkt_content);
		break;
	case 0x0806:
		arp_protocol_packet_handle(arg, pkt_header, pkt_content);
		break;
	case 0x0835:
		printf("==============RARP Protocol=================\n");
		printf("RARP\n");
		break;
	default:
		printf("==============Unknown Protocol==============\n");
		printf("Unknown Protocol\n");
		break;
	}
}
int main()
{
	pcap_if_t* alldevs; //适配器列表,它是一个链表的数据结构
	pcap_if_t* d; //保存某个适配器
	pcap_t* fp;
	int res;
	struct pcap_pkthdr* header;
	const u_char* pkt_data;
	time_t local_tv_sec;
	struct tm* ltime;
	char timestr[16];
	int count = 1;
	int i = 0, inum;
	char errbuf[PCAP_ERRBUF_SIZE];
	printf("===============Adapter List===============\n");
	//获取本地设备列表
	if (pcap_findalldevs(&alldevs, errbuf) == -1)
	{
		fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
		exit(1);
	}
	//htons()作用是将端口号由主机字节序转换为网络字节序的整数值。(host to net)
	//inet_addr()作用是将一个 IP 字符串转化为一个网络字节序的整数值,用于sockaddr_in.sin_addr.s_addr。
		//inet_ntoa()作用是将一个 sin_addr 结构体输出成 IP 字符串(network to ascii)。
		//输出列表
		for (d = alldevs; d != NULL; d = d->next)
		{
			//printf("%d. %s,addr:%s", ++i, d->name, d->addresses->addr->sa_data);
			printf("%d. %s,", ++i, d->name);
			if (d->description)
				printf(" (%s)\n", d->description);
			else
				printf(" (No description available)\n");
		}
	if (i == 0)
	{
		printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
		return -1;
	}
	//获取选择编号
	while (1)
	{
		printf("\nEnter the interface number (1-%d): ", i);
		scanf("%d",&inum);
		if (inum > 0 && inum <= i)
			break;
	}
	//跳到用户选择的适配器
	for (d = alldevs, i = 0; i < inum - 1; ++i, d = d->next);
	//打开适配器
	if ((fp = pcap_open_live(d->name,65536,1,1000,errbuf)) == NULL)
	{
		fprintf(stderr, "\nError openning adapter: %s\n", errbuf);
		pcap_freealldevs(alldevs);
		return -1;
	}
	//检查链路层的类型
	if (pcap_datalink(fp) != DLT_EN10MB)
	{
		fprintf(stderr, "This program only run on Ethernet networks\n");
		pcap_close(fp);
		pcap_freealldevs(alldevs);
		return -1;
	}
	printf("The program is working......\n");
	printf("The capture file is saving as 'data.txt'\n");
	printf("You can input 'ctrl + C' to stop the program\n");
	if ((file = freopen("data.txt", "w", stdout)) == 0)
		printf("Cannot open the file.\n");
	while ((res = pcap_next_ex(fp, &header, &pkt_data)) >= 0)
	{
		//超时
		if (res == 0)
			continue;
		//将时间戳转化为可识别格式
		local_tv_sec = header->ts.tv_sec;
		ltime = localtime(&local_tv_sec);
		strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);
		//输出编号、时间戳和包长度
		printf("============================================================================= = \n");
			printf("No.%d\ttime: %s\tlen: %ld\n", count++, timestr, header->len);
		printf("============================================================================= = \n");
			char temp[LINE_LEN + 1];
		//输出包
		for (i = 0; i < header->caplen; ++i)
		{
			printf("%.2x ", pkt_data[i]);
			if (isgraph(pkt_data[i]) || pkt_data[i] == ' ')
				temp[i % LINE_LEN] = pkt_data[i];
			else
				temp[i % LINE_LEN] = '.';
			if (i % LINE_LEN == 15)
			{
				temp[16] = '\0';
				printf(" ");
				printf("%s", temp);
				printf("\n");
				memset(temp, 0, LINE_LEN);
			}
		}
		printf("\n");
		//分析数据包
		ethernet_protocol_packet_handle(NULL, header, pkt_data);
	}
	if (res == -1)
	{
		printf("Error reading the packets: %s\n", pcap_geterr(fp));
		pcap_close(fp);
		pcap_freealldevs(alldevs);
		fclose(stdin);
		if (file)
			fclose(file);
		return -1;
	}
	//释放
	pcap_close(fp);
	pcap_freealldevs(alldevs);
	fclose(stdin);
	if (file)
		fclose(file);
	return 0;
}

将代码粘贴到Main.cpp里,如图:

点击运行:

结果如图所示:

成功啦!

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

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

相关文章

34、AD/DA

AD/DA介绍 AD&#xff08;Analog to Digital&#xff09;&#xff1a;模拟-数字转换&#xff0c;将模拟信号转换为计算机可操作的数字信号 DA&#xff08;Digital to Analog&#xff09;&#xff1a;数字-模拟转换&#xff0c;将计算机输出的数字信号转换为模拟信号 AD/DA转换…

离线数仓构建案例一

数据采集 日志数据&#xff08;文件&#xff09;到Kafka 自己写个程序模拟一些用户的行为数据&#xff0c;这些数据存在一个文件夹中。 接着使用flume监控采集这些文件&#xff0c;然后发送给kafka中待消费。 1、flume采集配置文件 监控文件将数据发给kafka的flume配置文件…

python scipy.cluster.hierarchy.dendrogram学习详记——(待完善)

1.Python scipy.cluster.hierarchy.dendrogram用法及代码示例 2.python dendrogram_Python中的凝聚层次聚类示例

微信小程序在线客服 全端通吃版+PC官网客服+H5网站客服+微信公众号客服 附带完整的搭建教程

随着互联网的快速发展&#xff0c;在线客服系统已经成为企业与用户沟通的重要桥梁。然而&#xff0c;许多企业在构建自己的在线客服系统时&#xff0c;往往面临多种平台、多端口的困扰&#xff0c;如何实现全端通吃的客服系统成为一项迫切的需求。为此&#xff0c;我们推出了一…

android.view.WindowLeaked解决方法

问题 我在使用WindowManager添加一个button&#xff0c; windowManager.addView(button,layoutParams);然后关闭当前的这个Activity的时候遇到了WindowLeak这个问题&#xff0c;也就是所谓的窗体泄露。 原因 主要原因是因为android只允许在UI主线程操作&#xff0c;我在使用W…

geoserver维度time

postgis创建date类型的字段 写入测试数据&#xff0c;对应flag&#xff0c;flag有不同的样式&#xff0c;这样方便观测 geoserver发布图层的时候设置“维度”启用 测试&#xff0c;设置了根据flag展示不同的颜色

本地源文件-丰富的图表-

D:\FineReport_11.0\webapps\webroot\WEB-INF\reportlets\demo\basic 图表类型:http://localhost:8075/webroot/help/demo.html 可视化图表&#xff0c;丰富的图表:help/demo.html http://localhost:8075/webroot/decision#management/directory 参数查询/条件查询与图…

使用Redis构建简易社交网站(1)-创建用户与动态界面

目的 本文目的&#xff1a;实现简易社交网站中创建新用户和创建新动态功能。&#xff08;完整代码附在文章末尾&#xff09; 相关知识 本文将教会你掌握&#xff1a;1.redis基本命令&#xff0c;2.python基本命令。 redis基本命令 hget&#xff1a;从哈希中获取指定域的值…

h5进行svga动画礼物特效播放的代码实现队列按顺序播放

需求描述&#xff1a; 在直播场景中&#xff0c;有很多的礼物特效动画&#xff0c;如采用Svga动画的播放方案&#xff0c;则会遇到以下问题&#xff1b; 1.svga文件的预加载&#xff0c; 2.动画的顺序播放队列。即前一个动画播放完了&#xff0c;才会播放下一个动画。 1.svg…

沉浸式观影怎么能少得了投影仪?极米轻薄投影极米Z7X了解一下

近段时间&#xff0c;各个平台好剧不断&#xff0c;《以爱为营》《宁安如梦》《乐源游》《无所畏惧》等优质好剧陆续开播&#xff0c;让剧迷们直呼看不过来。优质好剧已经开场&#xff0c;看好剧的装备当然也不能落下。现如今&#xff0c;大屏追剧已成潮流,极米Z7X陪大家一起开…

【笔记】Clion 中运行 C/C++11 之 CMakeLists.txt 的配置

该文章记录第一次使用 Clion 时&#xff0c;对 CMakeLists 的配置&#xff0c;使其能够运行 C/C11 的代码。 一. CMakeLists.txt 的配置 1、首先我们在需要新建一个项目 2、填写新建项目相关的信息 3、修改 CMakeLists.txt 文件内容 替换文本&#xff1a; # 使用此 CMakeLis…

两道面试题秒杀你的C++基础!

大家好&#xff0c;我是光城&#xff0c;今天发两个非常重要的面试题&#xff0c;可以留言区说出你的答案&#xff0c;这两个题目都比较重要&#xff0c;看你能答对不&#xff1f; 1.C中初始化变量有几种方式&#xff0c;各自有什么区别&#xff1f; 或者说Initialization分为哪…

数学建模-数据新动能驱动中国经济增长的统计研究-基于数字产业化和产业数字化的经济贡献测度

数据新动能驱动中国经济增长的统计研究-基于数字产业化和产业数字化的经济贡献测度 整体求解过程概述(摘要) 伴随着数据要素化进程的不断加深&#xff0c;对于数据如何作用于经济发展&#xff0c;数据与其他要素结合产生的动能应该如何测度的研究愈发重要。本文将数据新动能分…

MySQL性能调优-1-实际优化案例

关于SQL优化的思路&#xff0c;一般都是使用执行计划看看是否用到了索引&#xff0c;主要可能有两大类情况&#xff1a; 对业务字段建立了二级联合索引&#xff0c;但是MySQL错误地觉得走主键聚族索引全表扫描效率更高&#xff0c;而没有走二级索引 走二级索引&#xff0c;但…

LLM | 一文了解大语言模型中的参数高效微调(PEFT)

Parameter Efficient Fine Tuning(PEFT)也就是参数高效微调&#xff0c;是一种用于微调大型语言模型 &#xff08;LLM&#xff09; 的方法&#xff0c;与传统方法相比&#xff0c;它有效地降低了计算和内存需求。PEFT仅对模型参数的一小部分进行微调&#xff0c;同时冻结大部分…

9款热门API接口分享,值得收藏!

电商API接口 干货分享 开始 “ API是什么&#xff1f; API的主要目的是提供应用程序与开发人员以访问一组例程的能力&#xff0c;而又无需访问源码&#xff0c;或理解内部工作机制的细节。提供API所定义的功能的软件称作此API的实现。API是一种接口&#xff0c;故而是一种抽象…

使用PCSS实现的实时阴影效果

PCSS的技术可以使得阴影呈现出近硬远软的效果&#xff0c;并且能够实时实现。 其核心理念是通过模拟光源的面积来产生更自然、更柔和的阴影边缘。 具体步骤&#xff1a; 1、生成shadowmap 2、在进行阴影的比较时候进行平均&#xff0c;并非之前的shadow map 或者之后完全的阴影…

Xshell全局去除提示音

使用Xshell的时候经常会按TAB或者一些操作指令的时候的时候听到提示音&#xff0c;非常的烦 通常来说在Xshell中可以单独修改每一个会话的属性&#xff0c;将提示音关闭&#xff0c;但是新增的会话依然带有提示音&#xff0c;还得一个个的关闭&#xff0c;非常麻烦&#xff0c;…

【risc-v】易灵思efinix FPGA riscv 时钟配置的一些总结

系列文章目录 分享一些fpga内使用riscv软核的经验&#xff0c;共大家参考。后续内容比较多&#xff0c;会做成一个系列。 本系列会覆盖以下FPGA厂商 易灵思 efinix 赛灵思 xilinx 阿尔特拉 Altera 本文内容隶属于【易灵思efinix】系列。 文章目录 系列文章目录前言一、pan…

spring boot 事件机制

目录 概述实践监听spring boot ready事件代码 源码初始化流程调用流程 结束 概述 spring boot 版本为 2.7.17 。 整体看一下spring及spring boot 相关事件。 根据下文所给的源码关键处&#xff0c;打上断点&#xff0c;可以进行快速调试。降低源码阅读难度。 实践 spring…