《计算机网络》课后探研题书面报告_网际校验和算法
网际校验和算法
摘 要
本文旨在研究和实现网际校验和(Internet Checksum)算法。通过阅读《RFC 1071》文档理解该算法的工作原理,并使用编程语言实现网际校验和的计算过程。本项目将对不同类型的网络报文(包括ICMP、TCP、UDP等)进行差错检验,对捕获的报文进行校验和计算并验证其正确性。项目包括报文数据的读取、校验和的计算以及结果的输出展示等功能。本报告详细描述了算法的实现过程、测试方法和实验结果,并对网际校验和算法在网络通信中的应用进行了分析。通过本次探研,加深了对网络协议差错检测机制的理解,提高了协议分析与实现的能力。
关键字:网际校验和、差错检测、网络协议、报文验证
一、算法概述
网际校验和算法是一种简单且高效的错误检测机制,广泛应用于网络协议中,如IP、TCP、UDP等。其核心思想是在数据传输前生成一个校验和,并通过对数据进行分段求和及取反操作来实现错误检测。接收端通过相同的算法重新计算校验和,如果结果为全0,则说明数据传输过程中未发生错误。
1 算法原理
网际校验和算法由两个核心组件构成:校验和的生成与验证。在数据传输过程中,发送方负责生成校验和,而接收方则执行校验和的验证工作。下面是校验和的详细生成流程:
①数据分块:在算法开始时,首先将数据流划分为16位(2字节)为单位的字块。如果数据总长度不是16位的整数倍,则需要在末尾填充0来补足。
②把校验和字段置为0:在计算校验和之前,需要先将校验和字段的值置为0。这是因为校验和字段本身也会参与计算,但计算时应当使用0值。
③逐块求和:对每个16位字块进行加和,若产生进位(即求和结果超过16位,产生大于65535的结果),则将进位加回到结果的最低位。这个进位的处理是算法的关键,使得加法操作能避免丢失信息。
④按位取反:将上述求和结果按位取反(即对所有位进行反转),得到最终的校验和。取反操作是为了增强错误检测的能力,避免某些类型的错误模式(如全0或全1错误)无法被检测到。
校验和的验证则在接收端进行。在接收端,重新进行相同的求和和取反操作(不进行第②步)。如果最终结果是全0,则认为数据未发生错误;如果结果不是全0,则说明数据在传输过程中出现了错误。
该算法的设计使其能够快速且有效地检测常见的数据传输错误,如单比特错误、字节错误等。但它也有局限性,对于一些特定类型的错误(例如数据的字块顺序被改变)可能不敏感,因此它并不是一种完美的错误检测算法,但在多数应用场景下,已能满足需求。
2 算法特点
网际校验和算法在计算机网络中扮演着重要角色,其设计目标是通过简单的操作实现数据传输中的错误检测。由于其独特的特点和广泛的应用价值,该算法在多种网络协议中被广泛采用。以下将从多个方面介绍网际校验和算法的主要特点:
(1)简单高效:计算过程中仅需基本的加法和按位取反操作,执行效率较高,适合硬件加速实现,适用于实时性要求较高的应用场景。
(2)检错能力适中:能有效检测大多数单比特错误和字块错误,但对某些复杂的错误模式(如字节重排)敏感度较低。
(3)广泛应用:被广泛用于IP、TCP、UDP等网络协议中,尤其在需要高效和实时处理的环境中,已成为标准校验方法之一。
(4)实现灵活:由于其简单性,校验和的计算可以根据数据长度和类型的不同进行调整,灵活性较高。
3 算法应用
网际校验和算法因其独特的技术特征,在实际应用中具有广泛的实用价值。该算法凭借计算简便、检错能力适度等优势,已被广泛集成至各类网络协议和应用系统中,为数据传输的完整性与可靠性提供了有效保障。以下将详细介绍该算法在不同领域中的典型应用:
(1)网络通信协议:
- IP层(IPv4首部校验和):用于检测IP数据包的头部是否在传输过程中被篡改或损坏。
- 传输层(TCP、UDP报文段校验和):用于校验TCP和UDP报文段中的数据完整性,确保数据在传输过程中未被修改。
(2)数据完整性验证:
- 文件传输与存储完整性检测:校验和可用于验证文件传输过程中的数据完整性,确保文件未在传输中发生损坏。
- 网络设备数据包处理:网络设备通过校验和算法确保接收和转发的数据包完整性。
(3)嵌入式系统:
在嵌入式系统中,尤其是通信模块,使用该算法进行数据校验,确保通信过程中的数据不被篡改或丢失。
(4)网络安全与监控:
网络入侵检测与数据包分析工具:在安全系统中,算法可用于检测网络数据包中的错误或恶意篡改,从而保障网络的安全性。
二、编程实现
1 程序编写
下文将详细介绍如何通过编程实现网际校验和算法。本章节将从编程环境搭建开始,逐步说明代码实现的具体步骤、关键函数的设计思路以及数据处理的方法。通过这个实践过程,我们不仅能够深入理解网际校验和算法的工作原理,也能掌握如何将理论算法转化为可执行的程序代码。程序采用Python语言实现,代码结构清晰,便于理解和后续的维护与扩展。
1.1 编程环境
编程环境的正确配置是确保程序开发和运行顺利进行的重要前提。我选择了Windows 11作为开发平台,搭配功能强大的PyCharm作为集成开发环境,使用广受欢迎的Python编程语言,并将处理来自Wireshark工具导出的“.txt”格式数据文件。这些工具的选择既考虑了开发效率,也兼顾了程序的可移植性和扩展性。
- 操作系统:Windows 11
- 开发工具:PyCharm
- 编程语言:Python
- 数据文档格式:从Wireshark工具软件导出的原始数据包,为“.txt”格式。
图1 数据文档格式图
1.2 校验流程
本次编码不仅完成了对IP数据报首部的校验,还实现了ICMP、TCP、UDP报文的校验功能。鉴于整个实现流程较为复杂,此处仅展示IP数据报首部的关键校验流程。具体的IP数据报首部校验流程如下图所示(非标准流程图):
图2 IP数据报首部校验流程图
1.3 核心代码
鉴于IP报文首部校验和的计算与验证机制涉及多个分散的代码模块,此处仅展示其核心实现部分。完整的实现细节请参阅源代码。
(1)校验和计算函数`checksum_calculating`:实现标准的网际校验和算法,用于计算IP头部校验和。在函数中,校验和的计算流程如下:①从输入数据中检查长度,若为奇数则进行字节补齐;②对数据按16位为单位进行累加计算;③将进位加至最低位;④对最终结果取反得到校验和。具体代码如下图所示:
图3 校验和计算函数
(2)校验和验证函数`process_packet_to_string`:实现接收数据包的校验和验证。在函数中,校验和的验证流程如下:①从接收的IP首部中提取原始校验和;②构造用于校验和计算的IP首部数据;③调用`checksum_calculating`函数计算当前校验和;④将计算得到的校验和与原始校验和进行比对。部分代码如下图所示:
图4 校验和验证函数(部分)
2 程序测试
为验证程序的正确性,下面我将对我编写的用于网际校验和验证的程序进行测试。
2.1 测试文件
本次测试的数据文件均来自于计网实验5,从中选取典型的ICMP、UDP、TCP报文各一个。测试文件分别为“ICMP.txt”、“TCP.txt”、“UDP.txt”。这些文件包含了真实网络环境中的典型数据包,能够很好地验证算法在实际应用场景中的表现。测试文件内容格式如前文所述。
图5 测试文件
2.2 测试结果
(1)ICMP
下图是ICMP报文的具体内容,可以看到它的IP首部校验和为“f2 24”(图中蓝色高亮部分)。
图6 ICMP报文
下图是程序读取该报文后的测试结果,程序运行结果正确,与预期一致。
图7 ICMP报文测试结果
(2)TCP
下图是TCP报文的具体内容,可以看到它的IP首部校验和为“cd 6c”(图中蓝色高亮部分)。
图8 TCP报文
下图是程序读取该报文后的测试结果,程序运行结果正确,与预期一致。
图9 TCP报文测试结果
(3)UDP
下图是UDP报文的具体内容,可以看到它的IP首部校验和为“c0 d3”(图中蓝色高亮部分)。
图10 UDP报文
下图是程序读取该报文后的测试结果,程序运行结果正确,与预期一致。
图11 UDP报文测试结果
结 论
本次探研通过深入分析网际校验和算法的原理并进行实践实现,取得了以下主要成果:
(1)完成了网际校验和算法的理论研究和代码实现。通过研读《RFC 1071》文档,深入理解了该算法的工作原理,包括数据分块、校验和计算和验证等核心过程。研究表明该算法具有实现简单、计算效率高等特点,这也解释了其在网络协议中的广泛应用。
(2)成功开发了一个能够处理多种网络协议报文的校验程序。该程序不仅实现了IP数据报首部的校验,还扩展支持了ICMP、TCP、UDP等多种协议报文的校验功能。通过实际测试,程序能够正确计算和验证各类报文的校验和,验证结果与实际数据包中的校验和完全匹配。
(3)通过实践验证了网际校验和算法在差错检测方面的有效性。虽然该算法在某些特定错误模式(如字节重排)的检测上存在局限性,但其简单高效的特点使其非常适合网络通信中的实时差错检测需求。
(4)本次探研的实践过程加深了对网络协议差错检测机制的理解,提高了协议分析与实现的能力。通过编程实现和测试验证,不仅掌握了算法的技术细节,也认识到了在实际网络环境中确保数据传输可靠性的重要性。
总的来说,本次探研不仅完成了对网际校验和算法的理论学习和实践实现,还通过具体的程序开发和测试验证了该算法的实用价值。这些工作为进一步理解和应用网络协议中的差错检测机制奠定了基础。
参考文献
- Braden R, Borman D A, Partridge C. RFC 1071 Computing the Internet Checksum[S]. Fremont: RFC Editor, 1988.
- 李毅,张帆,张润宇.IPv4头部校验和的反码算法[J].武汉理工大学学报,2003,(04):64-68.
- 刘派.IP首部校验算法[J].电脑知识与技术,2010,6(19):5194-5196.
- 乔世成,张智丰,廉洁.IP首部校验和算法研究[J].内蒙古民族大学学报(自然科学版),2016,31(05):400-402.DOI:10.14045/j.cnki.15-1220.2016.05.010.
- 孔庆春.当前应用于计算机通信中的差错检测与控制技术[J].信息与电脑(理论版),2017,(18):146-148.
参考代码
import struct
import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtextdef checksum_calculating(data):"""计算给定数据的校验和(使用Internet Checksum算法)。参数:data (bytes): 要计算校验和的字节数据。返回:int: 计算得到的校验和。"""# 如果数据长度为奇数,补一个0字节if len(data) % 2 != 0:data += b'\x00'checksum = 0for i in range(0, len(data), 2):word = struct.unpack('!H', data[i:i + 2])[0]checksum += word# 处理进位while checksum >> 16:checksum = (checksum & 0xffff) + (checksum >> 16)checksum = ~checksum & 0xffffreturn checksumdef parse_ethernet_frame(data):"""解析以太网帧头,提取EtherType。参数:data (bytes): 以太网帧的字节数据。返回:tuple: (ethertype (int), payload (bytes))。异常:ValueError: 数据长度不足以解析以太网帧头。"""if len(data) < 14:raise ValueError("数据长度不足以解析以太网帧头")# 查找EtherType为0x0800(IPv4)的位置for i in range(len(data) - 2):if data[i] == 0x08 and data[i + 1] == 0x00:eth_header = data[:i + 2]payload = data[i + 2:]return 0x0800, payload# 如果未找到,使用标准解析方法eth_header = data[:14]eth_fields = struct.unpack('!6s6sH', eth_header)ethertype = eth_fields[2]payload = data[14:]return ethertype, payloaddef parse_ip_packet(data):"""解析IP数据包,提取协议类型和IP头部。参数:data (bytes): IP数据包的字节数据。返回:tuple: (protocol (int), ip_header (bytes), payload (bytes))。异常:ValueError: 数据长度不足以解析IP头部或完整的IP头部。"""if len(data) < 20:raise ValueError("数据长度不足以解析IP头部")version_ihl = data[0]ihl = (version_ihl & 0x0F) * 4 # 头部长度if len(data) < ihl:raise ValueError("数据长度不足以解析完整的IP头部")ip_header = data[:ihl]protocol = data[9]payload = data[ihl:]return protocol, ip_header, payloaddef parse_icmp_packet(data):"""解析ICMP数据包。参数:data (bytes): ICMP数据包的字节数据。返回:tuple: (icmp_type (int), icmp_code (int), icmp_data (bytes),received_checksum (int), checksum_data (bytes))。异常:ValueError: 数据长度不足以解析ICMP头部。"""if len(data) < 4:raise ValueError("数据长度不足以解析ICMP头部")icmp_header = data[:4]icmp_fields = struct.unpack('!BBH', icmp_header)icmp_type = icmp_fields[0]icmp_code = icmp_fields[1]received_checksum = icmp_fields[2]icmp_data = data[4:]# 创建用于计算校验和的数据(校验和字段置0)checksum_data = data[:2] + b'\x00\x00' + data[4:]return icmp_type, icmp_code, icmp_data, received_checksum, checksum_datadef parse_tcp_packet(data):"""解析TCP数据包。参数:data (bytes): TCP数据包的字节数据。返回:tuple: (src_port (int), dest_port (int), seq_num (int), ack_num (int),tcp_header_for_checksum (bytes), tcp_data (bytes),received_checksum (int))。异常:ValueError: 数据长度不足以解析TCP头部。"""if len(data) < 20:raise ValueError("数据长度不足以解析TCP头部")tcp_header = data[:20]tcp_fields = struct.unpack('!HHLLHHHH', tcp_header)src_port = tcp_fields[0]dest_port = tcp_fields[1]seq_num = tcp_fields[2]ack_num = tcp_fields[3]offset_reserved_flags = tcp_fields[4]window = tcp_fields[5]received_checksum = tcp_fields[6]urgent_pointer = tcp_fields[7]# 提取数据偏移、保留和标志位data_offset = (offset_reserved_flags >> 12) & 0xF # 数据偏移(高4位)reserved = (offset_reserved_flags >> 6) & 0x3F # 保留位(中间6位)flags = offset_reserved_flags & 0x3F # 标志位(低6位)data_offset = data_offset * 4tcp_data = data[data_offset:]# 校验和计算时,将校验和字段置零,但保留整个20字节头部tcp_header_for_checksum = tcp_header[:16] + b'\x00\x00' + tcp_header[18:20]return src_port, dest_port, seq_num, ack_num, tcp_header_for_checksum, tcp_data, received_checksumdef parse_udp_packet(data):"""解析UDP数据包。参数:data (bytes): UDP数据包的字节数据。返回:tuple: (src_port (int), dest_port (int), length (int),udp_header_for_checksum (bytes), udp_data (bytes),received_checksum (int))。异常:ValueError: 数据长度不足以解析UDP头部。"""if len(data) < 8:raise ValueError("数据长度不足以解析UDP头部")udp_header = data[:8]udp_fields = struct.unpack('!HHHH', udp_header)src_port = udp_fields[0]dest_port = udp_fields[1]length = udp_fields[2]received_checksum = udp_fields[3]udp_data = data[8:]# 将校验和字段置零用于计算udp_header_for_checksum = udp_header[:6] + b'\x00\x00'return src_port, dest_port, length, udp_header_for_checksum, udp_data, received_checksumdef hexstr_to_bytes(line):"""将十六进制字符串转换为字节数据。参数:line (str): 包含十六进制数的字符串,每个字节由两个十六进制字符表示,字节之间用'|'分隔。返回:bytes or None: 转换后的字节数据,如果转换失败则返回None。"""try:parts = line.strip().split('|')# 去除空白部分parts = [p.strip() for p in parts if p.strip()]if len(parts) > 1:parts = parts[1:] # 去掉偏移量字段# 确保每个部分有两个字符,不足则前置补零hex_pairs = [p.zfill(2) for p in parts]hex_cleaned = ''.join(hex_pairs)return bytes.fromhex(hex_cleaned)except Exception:return Nonedef process_packet_to_string(packet_bytes):"""处理数据包并将解析结果格式化为字符串。参数:packet_bytes (bytes): 要处理的数据包字节数据。返回:str: 格式化后的解析结果。"""result = []result.append(f"原始报文数据 ({len(packet_bytes)} 字节): {packet_bytes.hex()}")try:# 解析以太网帧ethertype, payload = parse_ethernet_frame(packet_bytes)result.append(f"以太网类型: 0x{ethertype:04x}")if ethertype == 0x0800: # IPv4protocol, ip_header, ip_payload = parse_ip_packet(payload)result.append(f"IP协议版本: {ip_header[0] >> 4}")result.append(f"IP首部长度: {(ip_header[0] & 0x0F) * 4} 字节")result.append(f"IP协议: {protocol}")# IP校验和received_ip_checksum = struct.unpack('!H', ip_header[10:12])[0]ip_header_for_checksum = ip_header[:10] + b'\x00\x00' + ip_header[12:]calculated_ip_checksum = checksum_calculating(ip_header_for_checksum)result.append(f"接收的IP校验和: 0x{received_ip_checksum:04x}")result.append(f"计算的IP校验和: 0x{calculated_ip_checksum:04x}")if received_ip_checksum == calculated_ip_checksum:result.append("IP校验和正确")else:result.append("IP校验和错误")if protocol == 1: # ICMPicmp_type, icmp_code, icmp_data, received_checksum, checksum_data = parse_icmp_packet(ip_payload)calculated_checksum = checksum_calculating(checksum_data)result.append(f"ICMP类型: {icmp_type}, 代码: {icmp_code}")result.append(f"ICMP接收的校验和: 0x{received_checksum:04x}")result.append(f"ICMP计算的校验和: 0x{calculated_checksum:04x}")if received_checksum == calculated_checksum:result.append("ICMP校验和正确")else:result.append("ICMP校验和错误")elif protocol == 6: # TCPsrc_port, dest_port, seq_num, ack_num, tcp_header_for_checksum, tcp_data, received_checksum = parse_tcp_packet(ip_payload)source_ip = ip_header[12:16] # 源IP地址destination_ip = ip_header[16:20] # 目的IP地址reserved_zero = b'\x00'protocol_byte = struct.pack('!B', protocol)segment_length = len(tcp_header_for_checksum) + len(tcp_data)tcp_length = struct.pack('!H', segment_length)# 构造伪头部用于校验和计算pseudo_header = source_ip + destination_ip + reserved_zero + protocol_byte + tcp_lengthchecksum_data = pseudo_header + tcp_header_for_checksum + tcp_dataif len(checksum_data) % 2 != 0:checksum_data += b'\x00'calculated_checksum = checksum_calculating(checksum_data)result.append(f"TCP源端口: {src_port}, 目的端口: {dest_port}")result.append(f"TCP接收的校验和: 0x{received_checksum:04x}")result.append(f"TCP计算的校验和: 0x{calculated_checksum:04x}")if received_checksum == calculated_checksum:result.append("TCP校验和正确")else:result.append("TCP校验和错误")elif protocol == 17: # UDPsrc_port, dest_port, length, udp_header_for_checksum, udp_data, received_checksum = parse_udp_packet(ip_payload)source_ip = ip_header[12:16] # 源IP地址destination_ip = ip_header[16:20] # 目的IP地址reserved_zero = b'\x00'protocol_byte = struct.pack('!B', protocol)udp_length = struct.pack('!H', length)# 构造伪头部用于校验和计算pseudo_header = source_ip + destination_ip + reserved_zero + protocol_byte + udp_lengthchecksum_data = pseudo_header + udp_header_for_checksum + udp_dataif len(checksum_data) % 2 != 0:checksum_data += b'\x00'calculated_checksum = checksum_calculating(checksum_data)result.append(f"UDP源端口: {src_port}, 目的端口: {dest_port}")result.append(f"UDP接收的校验和: 0x{received_checksum:04x}")result.append(f"UDP计算的校验和: 0x{calculated_checksum:04x}")if received_checksum == calculated_checksum:result.append("UDP校验和正确")else:result.append("UDP校验和错误")else:result.append(f"未支持的IP协议类型: {protocol}")else:result.append(f"未支持的以太网类型: 0x{ethertype:04x}")except ValueError as ve:result.append("解析报文时出错: " + str(ve))return '\n'.join(result)def main_gui():"""主函数,创建图形界面,选择文件,解析报文,计算校验和并显示结果。"""root = tk.Tk()root.title("网际校验和分析工具")root.geometry("800x600")# 创建可滚动文本区域显示结果text_area = scrolledtext.ScrolledText(root, wrap=tk.WORD, width=100, height=40)text_area.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)def select_file():"""处理文件选择和报文解析。"""file_path = filedialog.askopenfilename(title="选择测试文件",filetypes=(("文本文件", "*.txt"), ("所有文件", "*.*")))if not file_path:messagebox.showinfo("提示", "未选择任何文件。")returntry:with open(file_path, 'r', encoding='utf-8') as f:content = f.read().strip()packets = content.split('\n\n')output = []for packet in packets:lines = packet.strip().split('\n')if len(lines) < 2:continuedata_line = Nonefor line in lines:if line.startswith('|'):data_line = linebreakif not data_line:continuepacket_bytes = hexstr_to_bytes(data_line)if packet_bytes is None:output.append(f"无法解析的数据行: {data_line[:50]}...")continuepacket_result = process_packet_to_string(packet_bytes)output.append(packet_result)# 显示解析结果text_area.delete(1.0, tk.END)text_area.insert(tk.END, '\n\n'.join(output))except Exception as e:messagebox.showerror("错误", f"发生错误: {e}")# 创建选择文件并分析的按钮select_button = tk.Button(root, text="选择测试文件并分析", command=select_file)select_button.pack(pady=10)root.mainloop()if __name__ == "__main__":main_gui()
相关文章:

《计算机网络》课后探研题书面报告_网际校验和算法
网际校验和算法 摘 要 本文旨在研究和实现网际校验和(Internet Checksum)算法。通过阅读《RFC 1071》文档理解该算法的工作原理,并使用编程语言实现网际校验和的计算过程。本项目将对不同类型的网络报文(包括ICMP、TCP、UDP等&a…...

hot100_240. 搜索二维矩阵 II
hot100_240. 搜索二维矩阵 II 直接遍历列减行增 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性: 每行的元素从左到右升序排列。 每列的元素从上到下升序排列。 示例 1: 输入:matrix [[1,4,7,1…...

78_Redis网络模型
1.Redis网络模型概述 1.1 Redis网络模型介绍 Redis 7.x的网络模型基于epoll的Reactor模式实现,这是一个高效的事件驱动模型。在Redis中,所有的网络事件(如连接、读写等)都由一个事件循环(Event Loop)来处理。这个事件循环负责监听套接字上的事件,并根据事件类型调用相…...

python范围
用户图形界面-工资计算器 from tkinter import *def f():w int(e1.get()) int(e2.get()) - int(e3.get())wage.insert(0,w)root Tk() root.title("工资计算器") Label(root, text"每月基本工资:").pack() e1 Entry(root) e1.pack() Label(…...

vulnhub靶场【Raven系列】之2 ,对于mysql udf提权的复习
前言 靶机:Raven-2,IP地址为192.168.10.9 攻击:kali,IP地址为192.168.10.2 都采用虚拟机,网卡为桥接模式 文章所用靶机来自vulnhub,可通过官网下载,或者通过链接:https://pan.quark.cn/s/a65…...

基于vite+vue3+mapbox-gl从零搭建一个项目
下面是基于 Vite、Vue 3 和 Mapbox GL 从零搭建一个项目的完整步骤,包括环境搭建、依赖安装、配置和代码示例。 1. 初始化项目 首先,使用 Vite 快速创建一个 Vue 3 项目: npm create vuelatest vue3-mapboxgl --template vue cd vue3-mapbo…...

向harbor中上传镜像(向harbor上传image)
向 Harbor 中上传镜像通常分为以下几个步骤: 1、登录 Harbor 2、构建镜像 3、标记镜像 4、推送镜像到 Harbor 仓库 1、登录 Harbor 首先,确保你已经能够访问 Harbor,并且已经注册了账户。如果还没有 Harbor 账户,你需要先注册一…...

【线性代数】行列式的性质
行列式性质定理讲义 一、行列式的基本性质 性质 1:行列互换 对于任意一个 n n n \times n nn 的方阵 A A A,其行列式 ∣ A ∣ |A| ∣A∣ 满足: ∣ A ∣ ∣ A T ∣ |A| |A^T| ∣A∣∣AT∣ 其中, A T A^T AT 是 A A A 的…...

智能家居企业如何通过设计师渠道打造第二曲线?
随着智能家居行业的迅速发展和消费者需求的不断升级,企业的营销策略也在不断变化。传统的B2C营销模式逐渐让位于更加精细化、定制化的B2B2C模式,其中设计师渠道的开发与合作,成为智能家居企业布局市场、提升品牌影响力的关键。 智能家居推广的…...

Unity3d 实时天气系统基于UniStorm插件和xx天气API实现(含源码)
前言 实时天气在Unity3d三维数字沙盘中的作用非常重要,它能够增强虚拟环境的真实感和互动性,实时天气数据的应用可以提供更为精准和直观的天气信息支持,如果真实的数据加上特效、声音和模型反馈会提高产品档次,提高真实感。 目前…...

年后找工作需要注意的事项
大家好!我是 [数擎 AI],一位热爱探索新技术的前端开发者,在这里分享前端和 Web3D、AI 技术的干货与实战经验。如果你对技术有热情,欢迎关注我的文章,我们一起成长、进步! 开发领域:前端开发 | A…...

模拟器多开窗口单IP与代理IP关系
模拟器多开窗口同IP背后出现的问题 在游戏世界中,模拟器多开窗口是玩家们提升体验的常见做法。通过在同一设备上开启多个模拟器窗口,玩家可以同时运营多个游戏账号,增加游戏的趣味性和效率。 一旦检测到一个IP地址下登录了过多的账号&#x…...

Android ScrollView嵌套X5WebView大片空白问题
scrollview嵌套后webview的高度不可控。留有大片空白。 注:官方不建议scrollview嵌套webview 最好让webview自身滚动 解决方案: act_news_detail_wv.setWebViewClient(new WebViewClient() {Overridepublic void onPageFinished(WebView webView, Str…...

Java Web开发进阶——WebSocket与实时通信
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,广泛应用于需要实时数据交换的应用程序中。它能够实现服务器与客户端之间的双向通信,避免了传统 HTTP 请求/响应的延迟。结合 Spring Boot,开发实时通信应用变得更加高效与简便。 1. …...

zerotier搭建虚拟局域网,自建planet
基于该开源项目 自建planet节点,更快速,更安全 本教程依据docker-zerotier-planet 项目文档书写,并以linux(centos 7)和windows作为示例,需要其他系统配置方法,可移步项目文档 一. 前置资源 具有外网ip的服务器 后面…...

SQL面试题1:连续登陆问题
引言 场景介绍: 许多互联网平台为了提高用户的参与度和忠诚度,会推出各种连续登录奖励机制。例如,游戏平台会给连续登录的玩家发放游戏道具、金币等奖励;学习类 APP 会为连续登录学习的用户提供积分,积分可兑换课程或…...

2Spark Core
2Spark Core 1.RDD 详解1) 为什么要有 RDD?2) RDD 是什么?3) RDD 主要属性 2.RDD-API1) RDD 的创建方式2) RDD 的算子分类3) Transformation 转换算子4) Action 动作算子 3. RDD 的持久化/缓存4. RDD 容错机制 Checkpoint5. RDD 依赖关系1) 宽窄依赖2) 为什么要设计宽窄依赖 …...

linux之进程信号(初识信号,信号的产生)
目录 引入一、初识信号(信号预备知识)1.生活中的信号2.Linux中的信号3.信号进程得出的初步结论 二、信号的产生1.通过终端输入产生信号拓展: 硬件中断2.调用系统函数向进程发信号3.硬件异常产生信号4.软件条件产生信号拓展: 核心转储技术总结一下: 引入 一、初识信…...

基于nginx实现正向代理(linux版本)
介绍 在企业开发环境中,局域网内的设备通常需要通过正向代理服务器访问互联网。正向代理服务器充当中介,帮助客户端请求外部资源并返回结果。局域网内也就是俗称的内网,局域网外的互联网就是外网,在一些特殊场景内,例…...

【蓝牙】win11 笔记本电脑连接 hc-06
文章目录 前言步骤 前言 使用电脑通过蓝牙添加串口 步骤 设置 -> 蓝牙和其他设备 点击 显示更多设备 更多蓝牙设置 COM 端口 -> 添加 有可能出现卡顿,等待一会 传出 -> 浏览 点击添加 hc-06,如果没有则点击 再次搜索 确定 添加成…...

小程序组件 —— 31 事件系统 - 事件绑定和事件对象
小程序中绑定事件和网页开发中绑定事件几乎一致,只不过在小程序不能通过 on 的方式绑定事件,也没有 click 等事件,小程序中绑定事件使用 bind 方法,click 事件也需要使用 tap 事件来进行代替,绑定事件的方式有两种&…...

力扣cf补题-1【算法学习day.94】
前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向(例如想要掌握基础用法,该刷哪些题?建议灵神的题单和代码随想录)和记录自己的学习过程,我的解析也不会做的非常详细,只会提供思路和一些关…...

系统学习算法:专题四 前缀和
题目一: 算法原理: 这道题是一维前缀和的模板题,通过这道题我们可以了解什么是前缀和 题意很简单,就是先输入数组个数和查询次数,然后将数组的值放进数组,每次查询给2个数,第一个是起点&#x…...

java 迪米特法则,原理、思想、工作流程、实现细节、稳定性、优缺点、应用场景等
迪米特法则(Law of Demeter,LoD),也被称为“最少知识原则”,是一种指导面向对象设计的原则,旨在减少对象之间的耦合度。以下是对迪米特法则的详细解析。 1. 定义 迪米特法则指出:一个对象应该…...

vue项目引入阿里云svg资源图标
1:生成svg图标 登录阿里云官网 1.1 创建项目组 1.2 从阿里云网站上面获取喜欢的图标加入到已有的项目组 1.3 如果团队有自己的设计师,也可以让设计师上传自己的svg图标到阿里云指定的项目组; 使用的时候,把 资源包下载到本地项…...

存储过程和触发器
目录 1、存储过程 1.1 存储过程的概述 1.2 存储过程的类型 1. 系统存储过程 2. 本地存储过程 3. 临时存储过程 4. 扩展存储过程 1.3 T-SQL创建存储过程 1.4 T-SQL执行存储过程 1.5 T-SQL查看存储过程 1.6 T-SQL修改存储过程 1.7 T-SQL删除存储过程 2、触发器 2.1 …...

《拉依达的嵌入式\驱动面试宝典》—计算机网络篇(二)
《拉依达的嵌入式\驱动面试宝典》—计算机网络篇(二) 你好,我是拉依达。 感谢所有阅读关注我的同学支持,目前博客累计阅读 27w,关注1.5w人。其中博客《最全Linux驱动开发全流程详细解析(持续更新)-CSDN博客》已经是 Linux驱动 相关内容搜索的推荐首位,感谢大家支持。 《…...

【深度学习实战】kaggle 自动驾驶的假场景分类
本次分享我在kaggle中参与竞赛的历程,这个版本是我的第一版,使用的是vgg。欢迎大家进行建议和交流。 概述 判断自动驾驶场景是真是假,训练神经网络或使用任何算法来分类驾驶场景的图像是真实的还是虚假的。 图像采用 RGB 格式并以 JPEG 格式…...

Spring Boot 和微服务:快速入门指南
💖 欢迎来到我的博客! 非常高兴能在这里与您相遇。在这里,您不仅能获得有趣的技术分享,还能感受到轻松愉快的氛围。无论您是编程新手,还是资深开发者,都能在这里找到属于您的知识宝藏,学习和成长…...

qt QPainter setViewport setWindow viewport window
使用qt版本5.15.2 引入viewport和window目的是用于实现QPainter画出来的内容随着窗体伸缩与不伸缩两种情况,以及让QPainter在widget上指定的区域(viewport)进行绘制/渲染(分别对应下方demo1,demo2,demo3)。 setViewpo…...