【Python网络编程之DHCP服务器】
🚀 作者 :“码上有前”
🚀 文章简介 :Python开发技术
🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬
Python网络编程之DHCP服务器
- 代码见资源,效果图如下
- 一、实验要求
- 二、协议原理
- 2.1 DHCP协议
- 2.2 DHCP协议的特点
- 2.3 DHCP解决IP地址冲突
- 2.4 DHCP协议的应用:
- 三、分析程序代码
- 3.1 导入一些必要的库
- 3.2 启动主程序
- 3.3 编辑DHCP服务器流程
- 3.4 构建GUI界面
- 3.5 启动与暂停服务
- 3.6 运行服务
- 3.7 解析DHCP包
- 四、总结
- 五、参考文献
代码见资源,效果图如下
一、实验要求
- 基本要求:在理解 DHCP 协议的基础上,编写一个 DHCP 服务器,为网络中的主机动态分配 IP 地址等信息。
- 设计语言:Python、C/C++。
- 原理:根据 DHCP 工作过程,即 DHCP 正常工作的所需的几种 DHCP报文,在收到的客户的 DHCP 报文之后,服务器正确构造相应的 DHCP 响应报文并发送给 DHCP 客户。 4. 技术难点:分析收到 DHCP 客户发送的报文并正确发送响应 DHCP 报文。最终效果:计算机能从运行的 DHCP 服务器程序获取 IP 地址等信息,并能通过 whireshark 抓到相应的交互报文。
二、协议原理
2.1 DHCP协议
DHCP(Dynamic Host Configuration Protocol)是一种网络协议,用于在计算机网络中自动分配IP地址和其他网络参数。DHCP协议通过一种客户端/服务器模型工作,其中DHCP服务器负责分配IP地址和配置其他网络参数,而DHCP客户端则向服务器请求分配IP地址。
DHCP(Dynamic Host Configuration Protocol)是一种网络协议,旨在自动分配IP地址和其他网络参数给连接到网络的设备。它采用客户端/服务器模型,其中DHCP服务器负责分配IP地址和配置网络参数,而DHCP客户端向服务器请求获取这些信息。
DHCP协议的工作过程如下:
DHCP发现:当设备连接到网络时,它会发送一个DHCP发现消息(DHCP Discover),使用广播方式向网络中的所有设备发送请求。这个消息表明设备正在寻找一个DHCP服务器来获取IP地址和其他配置参数。
DHCP提供:收到DHCP发现消息的DHCP服务器会回复一个DHCP提供消息(DHCP Offer)。这个消息包含一个可用的IP地址和其他网络配置参数,如子网掩码、默认网关、DNS服务器等。DHCP服务器可以维护一个地址池,从中选择一个可用的IP地址分配给设备。
DHCP请求:设备接收到DHCP提供消息后,可以选择接受其中的一个提供。然后它会发送一个DHCP请求消息(DHCP Request),请求该提供的IP地址。
DHCP确认:DHCP服务器收到DHCP请求消息后,会发送一个DHCP确认消息(DHCP Acknowledgment),确认IP地址的分配和其他配置参数的提供。设备接收到确认消息后,会将分配的IP地址和配置参数应用到自身的网络接口上。
2.2 DHCP协议的特点
以下是DHCP协议的主要特点:
- 自动IP地址分配:DHCP允许网络中的设备在连接到网络时自动获取IP地址,而无需手动配置。这样可以简化网络管理,减少配置错误,并提高网络的可扩展性。
- 动态地址分配:DHCP允许IP地址的动态分配,这意味着设备可以在每次连接到网络时获得不同的IP地址。这对于移动设备或临时连接到网络的设备非常有用。
- 统一的网络参数配置:除了IP地址外,DHCP还可以配置其他网络参数,如子网掩码、默认网关、DNS服务器和其他自定义选项。通过集中管理这些参数,DHCP简化了网络配置和管理的过程。
- 地址租约管理:DHCP服务器分配给客户端的IP地址通常是有限时间的租约。租约到期后,客户端需要更新租约或重新请求IP地址。这种租约管理机制使得网络资源可以更好地利用,并且可以防止长时间未使用的IP地址占用网络地址空间。
2.3 DHCP解决IP地址冲突
当在DHCP网络中发生IP地址冲突时,DHCP协议采取以下步骤进行处理:
- IP地址检测:DHCP服务器在向客户端提供IP地址之前,会检测该地址是否已经在网络中被使用。这通常通过发送一个ARP请求(Address Resolution Protocol)来检查IP地址是否已被其他设备使用。如果收到ARP响应,表示IP地址已经被另一个设备占用,那么DHCP服务器会认为发生了IP地址冲突。
- IP地址冲突处理:一旦DHCP服务器检测到IP地址冲突,它会采取以下措施之一来解决冲突:
- 发送DHCP NAK消息:DHCP服务器可以发送一个DHCP NAK消息(Negative Acknowledgment)给客户端,通知其IP地址冲突,并要求客户端重新请求IP地址。客户端接收到DHCP NAK消息后,会放弃使用冲突的IP地址,并重新启动IP地址分配过程。
- 选择新的IP地址:DHCP服务器可以选择一个新的可用IP地址,并将其分配给客户端。这样避免了冲突的IP地址继续被使用,并确保网络中的设备都具有唯一的IP地址。
- 重新分配IP地址:在发生IP地址冲突后,客户端会重新启动IP地址获取过程。它会发送DHCP Discover消息,请求新的IP地址分配。DHCP服务器会检测并分配一个未被使用的IP地址给客户端。
需要注意的是,DHCP协议本身并不能完全防止IP地址冲突的发生,因为设备之间可能存在其他方式来手动配置IP地址。然而,DHCP协议的IP地址冲突处理机制可以帮助识别和解决冲突,确保网络中的设备获得唯一的IP地址,并减少IP地址冲突对网络正常运行的影响。
2.4 DHCP服务器IP分配三种方式
DHCP服务器可以采用以下三种方式来分配IP地址: - 随机分配(Random Allocation):在随机分配方式下,DHCP服务器从地址池中随机选择一个可用的IP地址并分配给客户端。这种方式简单快捷,但可能导致不同设备获得相同的IP地址,从而引发IP地址冲突。因此,随机分配通常适用于临时网络或不需要长期保留IP地址的场景。
- 动态分配(Dynamic Allocation):动态分配是DHCP协议的默认方式。在动态分配方式下,DHCP服务器从地址池中选择一个可用的IP地址分配给客户端,并为该IP地址设置一个租约时间。租约时间可以是固定的,也可以是可调整的。在租约到期之前,客户端可以一直使用该IP地址。一旦租约到期,客户端需要更新租约或重新请求IP地址。
- 静态分配(Static Allocation):静态分配是指在DHCP服务器上预先配置设备的IP地址分配。在这种方式下,DHCP服务器将特定的IP地址与设备的MAC地址(物理地址)进行绑定,并保持固定不变。当设备请求IP地址时,DHCP服务器会根据设备的MAC地址分配预先配置的IP地址。静态分配通常用于需要固定IP地址的设备,如服务器、打印机等。
需要注意的是,无论采用哪种方式,DHCP服务器都会维护一个地址池,其中包含可用的IP地址。服务器确保分配给客户端的IP地址是唯一的,并根据需要进行管理和更新。这样可以更有效地使用IP地址资源,并提供灵活的地址分配机制。
2.4 DHCP协议的应用:
DHCP协议在计算机网络中有广泛的应用,以下是一些主要的应用场景:
- 局域网(LAN)中的IP地址分配:在企业或家庭网络中,DHCP协议通常用于自动分配IP地址给局域网内的设备。当设备连接到网络时,它们可以通过DHCP请求自动获取IP地址和其他必要的网络参数,而无需手动配置每个设备的IP地址。
- 公共无线网络:在公共场所,如咖啡馆、机场或酒店等提供的无线网络中,DHCP协议可以用于动态分配IP地址给连接到网络的移动设备。这样用户可以方便地连接到网络而无需手动配置IP地址。
- VoIP电话系统:在VoIP(Voice over IP)电话系统中,DHCP协议可以用于为IP电话分配IP地址和其他必要的网络配置。当IP电话设备启动时,它可以通过DHCP请求获取与语音通信相关的网络参数。
- 网络管理:DHCP协议还可以用于网络管理中的一些任务。例如,管理员可以使用DHCP服务器来限制特定设备的访问权限或为特定设备提供特殊的网络配置。
总结起来,DHCP协议的主要应用领域是在计算机网络中自动分配IP地址和配置其他网络参数,以简化网络管理、提高可扩展性,并提供灵活的地址分配和配置机制。
三、分析程序代码
3.1 导入一些必要的库
上述代码片段引入了几个库:
tkinter
:这是 Python 的标准图形用户界面(GUI)库,用于创建窗口、按钮、标签等用户界面元素,实现图形化的应用程序。它提供了一套简单的接口,用于与用户进行交互。ttk
:这是 tkinter 的一个模块,提供了一套主题化的用户界面控件,包括按钮、标签、文本框等,可以用于创建更现代化和美观的用户界面。threading
:这是 Python 的一个内置模块,用于进行多线程编程。它提供了创建和管理线程的功能,可以在程序中同时执行多个任务,提高程序的并发性和响应性。socket
:这是 Python 的一个标准库,用于网络编程。它提供了创建和使用套接字(socket)的功能,用于在网络上进行通信,包括建立连接、发送和接收数据等。struct
:这也是 Python 的一个标准库,用于处理二进制数据和结构体。它提供了一组函数,用于将数据打包成二进制格式或从二进制格式解析数据,用于处理底层的网络通信和数据传输。
通过引入这些库,可以实现基于 tkinter 的图形化用户界面,同时通过 threading、socket 和 struct 等库来实现网络通信和数据处理的功能。
3.2 启动主程序
上述代码片段涉及到创建一个基于 tkinter 的图形化用户界面 (GUI) 应用程序的主要部分。
root = tk.Tk()
:这行代码创建了一个名为root
的顶级窗口对象,它将作为 GUI 应用程序的主窗口。dhcp_server_gui = DHCP_Server_GUI(root)
:这行代码创建了一个名为dhcp_server_gui
的DHCP_Server_GUI
对象,它是一个自定义的类的实例化对象。这个类应该是在其他地方定义的,它可能包含了创建用户界面的各种元素(例如按钮、标签、文本框等)以及处理用户交互的方法。root.mainloop()
:这行代码启动了主事件循环,它监听用户的输入和操作,并根据相应的事件进行响应。这个循环将一直运行,直到用户关闭应用程序的窗口。
综合来看,上述代码创建了一个 tkinter 的 GUI 应用程序,并通过DHCP_Server_GUI
类实例化对象来构建用户界面。然后,通过调用root.mainloop()
启动主事件循环,使应用程序可以响应用户的交互操作。
3.3 编辑DHCP服务器流程
在上述代码中,我们可以看到,首先我们对DHCP_Server|_GUI类进行了初始化,初始化之后,画出GUI界面 ,通过这个界面设置启动服务,停止服务,连接DHCP服务器等功能,同时在连接的过程中,我们需要对客户端发送给服务端的DHCP Dsicover进行构建与解析,DHCP Offer报文也同样要进行构建解析,这也是在本次实验中最具有难度的地方,一不小心就出错了,需要匹配参数类型与字节数,而且大都是一长串的,所以要非常的谨慎。
3.4 构建GUI界面
上述代码是一个自定义的 `DHCP_Server_GUI` 类的初始化方法 `__init__(self, root)`。
self.root = root
:将传入的root
对象保存为类的属性,以便后续在类的其他方法中使用。self.root.title("DHCP 服务器")
:设置窗口的标题为 “DHCP 服务器”。self.root.geometry("400x300")
:设置窗口的大小为宽度 400 像素,高度 300 像素。self.start_button = ttk.Button(self.root, text="启动服务器", command=self.start_server)
:创建一个名为start_button
的 ttk.Button 对象,显示文本为 “启动服务器”,并设置点击按钮时调用self.start_server
方法。self.start_button.pack(pady=20)
:将start_button
按钮放置在窗口中,并设置垂直方向上的间距为 20 像素。self.stop_button = ttk.Button(self.root, text="停止服务器", command=self.stop_server, state=tk.DISABLED)
:创建一个名为stop_button
的 ttk.Button 对象,显示文本为 “停止服务器”,并设置点击按钮时调用self.stop_server
方法。同时,设置按钮的状态为tk.DISABLED
,即初始状态下禁用该按钮。self.stop_button.pack(pady=10)
:将stop_button
按钮放置在窗口中,并设置垂直方向上的间距为 10 像素。self.status_label = ttk.Label(self.root, text="服务器未启动", font=("Arial", 12))
:创建一个名为status_label
的 ttk.Label 对象,显示文本为 “服务器未启动”,使用 Arial 字体,字号为 12。self.status_label.pack(pady=10)
:将status_label
标签放置在窗口中,并设置垂直方向上的间距为 10 像素。self.client_info_treeview = ttk.Treeview(self.root, columns=("IP", "MAC"), show="headings")
:创建一个名为client_info_treeview
的 ttk.Treeview 对象,显示两列,列标识符分别为 “IP” 和 “MAC”,并设置显示表头。self.client_info_treeview.heading("IP", text="IP 地址")
:设置表头 “IP” 的显示文本为 “IP 地址”。self.client_info_treeview.heading("MAC", text="MAC 地址")
:设置表头 “MAC” 的显示文本为 “MAC 地址”。self.client_info_treeview.pack(pady=10)
:将client_info_treeview
的 Treeview 放置在窗口中,并设置垂直方向上的间距为 10 像素。self.server_socket = None
:初始化属性server_socket
为None
,用于存储服务器的套接字对象。self.server_thread = None
:初始化属性server_thread
为None
,用于存储服务器的线程对象。self.stop_event = threading.Event()
:创建一个名为stop_event
的 threading.Event() 对象,用于在停止服务器时发送停止信号。
综合来看,上述代码初始化了 DHCP 服务器的图形化用户界面,包括启动和停止服务器的按钮、服务器状态的标签、客户端信息的表格以及与服务器相关的属性。
最后我们讲得到的ip地址与mac地址插入到GUI界面中。
3.5 启动与暂停服务
上述代码是 DHCP_Server_GUI
类中的 start_server
方法的实现。
self.start_button.config(state=tk.DISABLED)
:将start_button
按钮的状态设置为tk.DISABLED
,即禁用该按钮,防止用户重复点击启动服务器。self.stop_button.config(state=tk.NORMAL)
:将stop_button
按钮的状态设置为tk.NORMAL
,即启用该按钮,允许用户点击停止服务器。self.status_label.config(text="服务器运行中", foreground="green")
:将status_label
标签的文本设置为 “服务器运行中”,并将文本颜色设置为绿色,以表示服务器正在运行。self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
:创建一个 UDP 套接字对象,用于接收和发送数据包。self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
:设置套接字选项,允许地址重用,以便在服务器关闭后能够快速重新启动。self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
:设置套接字选项,允许发送广播数据包。self.server_socket.bind(('192.168.1.5', 67))
:将服务器套接字绑定到本地 IP 地址为 ‘192.168.1.5’,端口号为 67。这意味着服务器将监听该地址和端口上的数据包。self.server_thread = threading.Thread(target=self.run_server)
:创建一个名为server_thread
的线程对象,目标函数为self.run_server
,即运行服务器的方法。self.server_thread.start()
:启动server_thread
线程,开始运行服务器。
综合来看,上述代码实现了启动服务器的操作。它禁用了启动按钮,启用了停止按钮,并更新了服务器状态标签的文本和颜色。然后,创建了一个 UDP 套接字对象,并设置了一些套接字选项。接下来,绑定了套接字到指定的 IP 地址和端口号。最后,创建并启动了一个线程,用于执行服务器的运行逻辑。
上述代码是 DHCP_Server_GUI
类中的 stop_server
方法的实现。
self.start_button.config(state=tk.NORMAL)
:将start_button
按钮的状态设置为tk.NORMAL
,即启用该按钮,允许用户点击启动服务器。self.stop_button.config(state=tk.DISABLED)
:将stop_button
按钮的状态设置为tk.DISABLED
,即禁用该按钮,防止用户重复点击停止服务器。self.status_label.config(text="服务器已停止", foreground="red")
:将status_label
标签的文本设置为 “服务器已停止”,并将文本颜色设置为红色,以表示服务器已停止。self.stop_event.set()
:设置stop_event
事件,向服务器线程发送停止信号。self.server_thread.join()
:等待服务器线程完成执行,即等待服务器线程结束。self.server_socket.close()
:关闭服务器套接字,释放相关的系统资源。
综合来看,上述代码实现了停止服务器的操作。它启用了启动按钮,禁用了停止按钮,并更新了服务器状态标签的文本和颜色。然后,设置了停止事件,向服务器线程发送停止信号。接着,等待服务器线程执行结束,并关闭服务器套接字,释放相关资源。
3.6 运行服务
在4.5节中,我们提到start_server中启动程序和线程,因此调动了run_server方法。接下来我们详细解释一下这个方法。
上述代码是 DHCP_Server_GUI
类中的 run_server
方法的实现。
while not self.stop_event.is_set():
:在停止事件stop_event
未被设置的情况下循环执行以下代码,即只要停止事件未发生,就继续运行服务器。data, addr = self.server_socket.recvfrom(1024)
:从服务器套接字接收最多 1024 字节的数据,并将数据和发送方地址保存到data
和addr
变量中。request_packet = self.parse_dhcp_packet(data)
:调用parse_dhcp_packet
方法解析接收到的 DHCP 报文,将解析结果保存到request_packet
变量中。if request_packet[0] == 1:
:判断解析后的 DHCP 报文的第一个字段是否为 1,即判断是否为 DHCP Discover 报文。offer_packet = self.create_dhcp_offer(request_packet)
:调用create_dhcp_offer
方法创建 DHCP Offer 报文,将 DHCP Discover 报文作为参数传入,并将创建的报文保存到offer_packet
变量中。self.server_socket.sendto(offer_packet, addr)
:将 DHCP Offer 报文通过服务器套接字发送给客户端的地址addr
。self.update_client_info(addr[0], request_packet[11:12])
:调用update_client_info
方法,将客户端的 IP 地址和 MAC 地址作为参数传入,用于更新客户端信息。except socket.timeout: continue
:捕获套接字超时异常,如果发生超时,则继续循环等待接收数据。
综合来看,上述代码实现了服务器的主要逻辑。它通过循环接收客户端发送的 DHCP 报文,判断报文类型并创建相应的回复报文,并将回复报文发送给客户端。同时,更新客户端的信息。如果发生套接字超时异常,则继续等待接收数据。
3.7 解析DHCP包
上述代码是 DHCP_Server_GUI
类中的 parse_dhcp_packet
方法的实现。
dhcp_format = '!BBBBLHHLLLL16s64s128sBBBBBB'
:定义了一个格式字符串dhcp_format
,用于指定 DHCP 报文的解析格式。该格式字符串描述了 DHCP 报文中各个字段的类型、顺序和长度。print("dhcp_format==",dhcp_format,len(dhcp_format))
:打印格式字符串dhcp_format
的值和长度,用于调试和确认格式字符串的正确性。request_packet = struct.unpack(dhcp_format, data)
:使用struct.unpack
函数根据格式字符串dhcp_format
将接收到的二进制数据data
解析成一个元组。解析结果保存在request_packet
变量中。return request_packet
:返回解析后的 DHCP 报文,即一个包含各个字段值的元组。
请注意,struct.unpack
函数根据提供的格式字符串将二进制数据解析为指定的类型和顺序。确保提供给struct.unpack
函数的数据长度与格式字符串所需的长度一致,并确保格式字符串与要解包的数据的结构相匹配,包括字段的数量、类型和顺序。这可以确保正确解析 DHCP 报文并获得所需的字段值。
构建DHCP Offer报文,在这里我们根据DHCP协议报文的格式,进行报文的打包,在这里比较麻烦,要一个一个区匹配每个参数,以及参数的大小与类型,所以非常容易出错并且难以查找问题,因此我们使用这种分开形式来进行打包,这样就非常容易匹配而且很轻松的维护。
四、总结
在上述实验中,我们实现了一个简化的 DHCP 服务器,用于为网络中的主机动态分配 IP 地址和其他配置信息。通过理解 DHCP 协议的工作原理和报文格式,我们成功地构建了一个基本的 DHCP 服务器,并实现了以下功能和流程:
- 服务器设置:我们通过创建一个 socket 对象,将其绑定到服务器的网络接口上,以侦听和接收 DHCP 客户端的请求报文。
- DHCP 请求处理:服务器通过循环持续监听 DHCP 客户端的请求报文。一旦收到请求报文,就进行以下处理:
- 解析报文:服务器解析 DHCP 请求报文,提取相关信息,如消息类型、客户端标识和请求的选项等。
- DHCP 响应构建:根据消息类型,服务器生成相应的 DHCP 响应报文。对于 DHCP Discover 消息,服务器构建 DHCP Offer 报文;对于 DHCP Request 消息,服务器构建 DHCP Ack 报文。
- 填充配置信息:服务器在 DHCP 响应报文中填充必要的配置信息,如分配的 IP 地址、子网掩码、默认网关、DNS 服务器和租约时间等。
- 发送响应报文:服务器将构建好的 DHCP 响应报文发送给相应的 DHCP 客户端,以完成 IP 地址和配置信息的分配过程。
- IP 地址管理:服务器在成功分配 IP 地址后,更新自己的 IP 地址分配表,将所分配的 IP 地址标记为已使用状态。
- 可选操作:如果需要,可以实现租约续约、租约过期和 IP 地址释放等机制,以确保 IP 地址的有效管理和可靠分配。
通过以上步骤,我们成功地实现了一个基本的 DHCP 服务器,能够为网络中的主机动态分配 IP 地址和其他配置信息,实现了 DHCP 协议中客户端和服务器之间的交互过程。
· 值得注意的是,上述实验中的 DHCP 服务器只是一个简化版本,具有基本的功能和流程。实际的 DHCP 服务器可能需要更多的功能和复杂性,例如处理更多的 DHCP 选项、支持多个 IP 地址池、实现租约管理和日志记录等。因此,在实际部署 DHCP 服务器时,需要根据具体需求进行进一步的开发和配置。
总之,通过实现 DHCP 服务器,我们深入理解了 DHCP 协议的工作原理,并学习了如何动态分配 IP 地址和配置信息给网络中的主机。这对于构建和管理大型网络以及提供自动化的网络配置是非常重要的。
五、参考文献
以下是一些参考文献,结合 DHCP 协议和相关实验,可以帮助您更深入地了解 DHCP 的工作原理和实现:
- RFC 2131: Dynamic Host Configuration Protocol (DHCP):这是 DHCP 协议的官方规范文档,提供了关于 DHCP 协议的详细描述,包括消息格式、选项字段和协议行为等。
- RFC 2132: DHCP Options and BOOTP Vendor Extensions:该文档扩展了 RFC 2131 中定义的 DHCP 选项,并介绍了 BOOTP 厂商扩展的使用。
- RFC 1542: Clarifications and Extensions for the Bootstrap Protocol:此文档提供了对 DHCP 前身 BOOTP 协议的补充和扩展,为理解 DHCP 提供了背景和历史。
- “DHCP Handbook” by Ralph Droms and Ted Lemon:这是一本详细介绍 DHCP 协议和实现的实用手册,对 DHCP 的工作原理、报文格式和服务器实现进行了全面的讲解。
- “TCP/IP Illustrated, Volume 1: The Protocols” by W. Richard Stevens:该书深入介绍了 TCP/IP 协议族,包括 DHCP 在内的各种协议,提供了对 DHCP 的详细解释和示例。
- “DHCP for Windows 2000: Managing the Dynamic Host Configuration Protocol” by Neall Alcott:这本书针对 Windows 2000 平台的 DHCP 实现进行了阐述,包括服务器配置、管理和故障排除等方面的内容。
- “The DHCP Handbook” by Ralph Droms and Ted Lemon:这本书提供了全面的 DHCP 指南,包括协议的详细说明、服务器和客户端的实现示例以及网络配置的最佳实践。
- “DHCP: A Guide to Dynamic TCP/IP Network Configuration” by Berry Kercheval:该书提供了关于 DHCP 的全面介绍,从基础概念到实际部署和故障排除,涵盖了各个方面的知识
- “Practical Packet Analysis: Using Wireshark to Solve Real-World Network Problems” by Chris Sanders:Wireshark 是一款常用的网络抓包工具,本书介绍了如何使用 Wireshark 分析网络流量,包括 DHCP 的抓包和分析技巧。
都看到这啦,点个赞吧🚀
相关文章:
【Python网络编程之DHCP服务器】
🚀 作者 :“码上有前” 🚀 文章简介 :Python开发技术 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 Python网络编程之DHCP服务器 代码见资源,效果图如下一、实验要求二、协议原理2.1 D…...
【MySQL】:深入理解并掌握DML和DCL
🎥 屿小夏 : 个人主页 🔥个人专栏 : MySQL从入门到进阶 🌄 莫道桑榆晚,为霞尚满天! 文章目录 📑前言一. DML1.1 添加数据1.2 修改数据1.3 删除数据 二. DCL2.1 管理用户2.2 权限控制…...
CSP-动态规划-最长公共子序列(LCS)
一、动态规划 动态规划(Dynamic Programming,简称DP)主要用于求解可以被分解为相似子问题的复杂问题,特别是在优化问题上表现出色,如最短路径、最大子数组和、编辑距离等。动态规划的核心思想是将原问题分解为较小的子…...
安装nodejs2011并配置npm仓库
1. 安装nodejs 选择2011版本下载 在安装目录(个人情况)下 D:\Program Files\nodejs2011创建2个文件夹: node_global (依赖库) node_cache (缓存) 然后在当前目录下cmd进入dos窗口,执行: npm c…...
排序C++代码(已更:快速排序,归并排序)
一、快速排序 #include<iostream> using namespace std;//设定三个数组,判断排序算法代码的正确性 int a[100]{3,4,2,6,9,7,1,0,1,2,3,3,5,6,7,8,3,4,5}; int b[100]{1,5,3,4}; int c[100]{7,8,9,1,2,3};void quickSort(int* num,int l,int r){if(l>r) re…...
CentOS 7.9安装Tesla M4驱动、CUDA和cuDNN
正文共:1333 字 21 图,预估阅读时间:2 分钟 上次我们在Windows上尝试用Tesla M4配置深度学习环境(TensorFlow识别GPU难道就这么难吗?还是我的GPU有问题?),但是失败了。考虑到Windows…...
Java设计模式——策略
前言 策略模式是平时Java开发中常用的一种,虽然已有很多讲解设计模式的文章,但是这里还是写篇文章来从自己理解的角度讲解一下。 使用场景 我们不妨进行场景假设,要对我们的软件进行授权管理:在启动我们的软件之前先要校验是否…...
线性代数的本质 1 向量
向量是线性代数中最为基础的概念。 何为向量? 从物理上看, 向量就是既有大小又有方向的量,只要这两者一定,就可以在空间中随便移动。 从计算机应用的角度看,向量和列表很接近,可以用来描述某对象的几个不同…...
基于JAVA的贫困地区人口信息管理系统 开源项目
目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 人口信息管理模块2.2 精准扶贫管理模块2.3 特殊群体管理模块2.4 案件信息管理模块2.5 物资补助模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 人口表3.2.2 扶贫表3.2.3 特殊群体表3.2.4 案件表3.2.5 物资补助表 四…...
【后端高频面试题--Mybatis篇】
🚀 作者 :“码上有前” 🚀 文章简介 :后端高频面试题 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 后端高频面试题--Mybatis篇 什么是Mybatis?Mybatis的优缺点?Mybatis的特点…...
【笔记】Helm-5 Chart模板指南-12 .helmignore文件
.helmignore文件 .helmignore文件用来指定您不想包含在您的helm chart中的文件。 如果该文件存在,helm package命令会在打包应用时忽略所有在.helmignore文件中匹配的文件。 有助于避免不需要的或敏感文件及目录添加到您的helm chart中。 .helmignore文件支持Uni…...
【MySQL】表的增删改查(基础)
MySQL表的增删改查(基础) 1. CRUD2. 新增(Create)2.1 单行数据全列插入2.2 多行数据 指定列插入 3. 查询(Retrieve)3.1 全列查询3.2 指定列查询3.3 查询字段为表达式3.4 别名3.5 去重:DISTINCT…...
Android矩阵Matrix动画缩放Bitmap移动手指触点到ImageView中心位置,Kotlin
Android矩阵Matrix动画缩放Bitmap移动手指触点到ImageView中心位置,Kotlin 借鉴 Android双指缩放ScaleGestureDetector检测放大因子大图移动到双指中心点ImageView区域中心,Kotlin(2)-CSDN博客 在此基础上实现手指在屏幕上点击后&…...
C语言:表达式求值
引言:在笔试中,有一类的题目,题目给出代码,要求分析得出输出结果。这类题目更加考察我们对于运算顺序和运算类型转换的理解。文章介绍了隐式类型转换和操作符注意点,希望增加读者对于表达式求值的理解。 1.隐式类型转…...
GO 的 Web 开发系列(五)—— 使用 Swagger 生成一份好看的接口文档
经过前面的文章,已经完成了 Web 系统基础功能的搭建,也实现了 API 接口、HTML 模板渲染等功能。接下来要做的就是使用 Swagger 工具,为这些 Api 接口生成一份好看的接口文档。 一、写注释 注释是 Swagger 的灵魂,Swagger 是通过…...
【极数系列】Flink集成KafkaSink 实时输出数据(11)
文章目录 01 引言02 连接器依赖2.1 kafka连接器依赖2.2 base基础依赖 03 使用方法04 序列化器05 指标监控06 项目源码实战6.1 包结构6.2 pom.xml依赖6.3 配置文件6.4 创建sink作业 01 引言 KafkaSink 可将数据流写入一个或多个 Kafka topic 实战源码地址,一键下载可用…...
我为什么选择Xamarin开发ios app安卓app
临岁之寒简书作者,转载 Xamarin是一项跨平台开发技术,之前是收费的,而且据说收费不菲,所以使用的人数比较少,在国内几乎无人问津。后来Xamarin被微软收购,现已免费开放,相信今后国内的使用人群会大幅地增长…...
安全基础~通用漏洞4
文章目录 知识补充XSS跨站脚本**原理****攻击类型**XSS-后台植入Cookie&表单劫持XSS-Flash钓鱼配合MSF捆绑上线ctfshow XSS靶场练习 知识补充 SQL注入小迪讲解 文件上传小迪讲解 文件上传中间件解析 XSS跨站脚本 xss平台: https://xss.pt/ 原理 恶意攻击者…...
2024/2/12 图的基础知识 2
目录 查找文献 P5318 【深基18.例3】查找文献 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 有向图的拓扑序列 848. 有向图的拓扑序列 - AcWing题库 最大食物链计数 P4017 最大食物链计数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 查找文献 P5318 【深基18.例3】…...
无人机飞行原理,多旋翼无人机飞行原理详解
多旋翼无人机升空飞行的首要条件是动力,有了动力才能驱动旋粪旋转,才能产生克服重力所必需的升力。使旋翼产生升力,进而推动多旋翼无人机升空飞行的一套设备装置称为动力装置,包括多旋翼无人机的发动机以及保证发动机正常工作所必…...
docker本地目录挂载
小命令 1、查看容器详情 docker inspect 容器名称 还是以nginx为例,上篇文章我们制作了nginx静态目录的数据卷,此时查看nginx容器时会展示出来(docker inspect nginx 展示信息太多,这里只截图数据卷挂载信息)&#…...
使用C++从零开始,自己写一个MiniWeb
第一步:新建项目 1、打开VS点击创建新项目 2、选择空项目并点下一步(切记不能选错项目类型) 3、填写项目名称和路径,点击创建即可 新建好后项目是这样的比较干净 4、右击源文件,点击添加,新建http.cpp文件…...
Android Graphics 图像显示系统 - 开篇
“ 随着学习的不断深入和工作经验的积累,欲将之前在博客中整理的Android Graphics知识做进一步整理,并纠正一些理解上的错误,故开设Graphics主题系列文章 ” 序言 由于工作需要,也源于个人兴趣,终于下决心花时间整理一…...
机器学习在各个行业的应用介绍
随着科技的飞速发展,机器学习已经从实验室走向了现实世界,逐渐成为各行各业不可或缺的工具。从金融领域到医疗健康,从零售市场到制造业,机器学习正在改变着我们的工作方式和生活质量。 本文将深入探讨机器学习在以下几个领域的应用…...
【生产实测有效】Windows命令行查看激活状态脚本
Windows查看激活状态关键代码 通过windows server 自带的PowerShell来执行 Get-WmiObject SoftwareLicensingProduct | Select-Object -Property Description, LicenseStatus | findstr "Operating System"|findstr "1$"Get-WmiObject SoftwareLicensingPr…...
简单的Udp服务器
目录 简单的UDP网络程序1.1 UdpServer.hpp1.2 UdpClient.cc1.3 main.cc1.4 makefile1.5 log.hpp 简单的UDP网络程序 1.1 UdpServer.hpp #pragma once#include <iostream> using namespace std;#include <unistd.h> #include <sys/types.h> #include <sy…...
【Linux进程间通信】用管道实现简单的进程池、命名管道
【Linux进程间通信】用管道实现简单的进程池、命名管道 目录 【Linux进程间通信】用管道实现简单的进程池、命名管道为什么要实现进程池?代码实现命名管道创建一个命名管道 理解命名管道匿名管道与命名管道的区别命名管道的打开规则 作者:爱写代码的刚子…...
Linux操作系统基础(九):Linux用户与权限
文章目录 Linux用户与权限 一、文件权限概述 二、终端命令:组管理 三、终端命令:用户管理 1、创建用户 、 设置密码 、删除用户 2、查看用户信息 3、su切换用户 4、sudo 4.1、给指定用户授予权限 4.2、使用 用户 zhangsan登录, 操作管理员命令…...
蓝桥杯——第 5 场 小白入门赛(c++详解!!!)
文章目录 1 十二生肖基本思路: 2 欢迎参加福建省大学生程序设计竞赛基本思路:代码: 3 匹配二元组的数量基本思路:代码: 4 元素交换基本思路:代码: 5 下棋的贝贝基本思路:代码: 6 方程…...
Codeforces Round 303 (Div. 2)C. Kefa and Park(DFS、实现)
文章目录 题面链接题意题解代码总结 题面 链接 C. Kefa and Park 题意 求叶节点数量,叶节点满足,从根节点到叶节点的路径上最长连续1的长度小于m 题解 这道题目主要是实现,当不满足条件时直接返回。 到达叶节点后统计答案,用…...
797. 差分
Problem: 797. 差分 文章目录 思路解题方法复杂度Code 思路 这是一个差分数组的问题。差分数组的主要适用场景是频繁对原始数组的某一个区间进行增减操作。这种操作是区间修改操作,在这种操作下,差分数组只需要对区间的两个端点进行操作,时间…...
2024.2.5 vscode连不上虚拟机,始终waiting for server log
昨天还好好的,吃着火锅,做着毕设,突然就被vscode给劫了。 起初,哥们跟着网上教程有模有样地删除了安装包缓存,还删除了.vscode-server,发现没卵用,之前都是搜那个弹窗报错。 后来发现原来是vsco…...
CSS基础---新手入门级详解
CSS:层叠样式表 CSS(Cascading Style Sheets,层叠样式表),是一种用来为结构化文档添加样式(字体、间距和颜色)的计算机语言,css扩展名为.css。 实例: <!DOCTYPE html><html> <head><…...
Python中Pymysql库的常见用法和代码示例
关注B站可以观看更多实战教学视频:肆十二-的个人空间-肆十二-个人主页-哔哩哔哩视频 (bilibili.com) pymysql是一个用于连接MySQL数据库的Python库,它允许你执行SQL查询并处理返回的结果。以下是pymysql库的一些常见用法和代码示例: 1. 安装…...
使用 WPF + Chrome 内核实现高稳定性的在线客服系统复合应用程序
对于在线客服与营销系统,客服端指的是后台提供服务的客服或营销人员,他们使用客服程序在后台观察网站的被访情况,开展营销活动或提供客户服务。在本篇文章中,我将详细介绍如何通过 WPF Chrome 内核的方式实现复合客服端应用程序。…...
fastapi mysql 开发restful 3
pip install mysql-connector-python pymysql 数据库链接 创建src目录,里面创建db.py 代码如下: # 导入mysql.connector模块,该模块提供了与MySQL数据库进行连接和交互的功能。 import mysql.connector # 定义一个函数get_db_connectio…...
【Uniapp uni-app学习与快速上手——详细讲解】
Uniapp uni-app学习与快速上手——详细讲解 1. 介绍2. Uni-app 学习资源3. 快速上手4. 开始第一个项目5. 调试和发布 1. 介绍 Uni-app 是一个使用 Vue.js 编写多端应用的前端框架。开发者可以编写一份代码,然后发布到iOS、Android、网页(响应式…...
剑指offer——旋转数组的最小数字
目录 1. 题目描述2. 分析思路2.1 示例分析 3. 更完美的做法 1. 题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3.4,5,1.2}为{1.2,3,4,5}的一个旋转&a…...
盘点数据可视化大屏焦点图十种样式
所谓焦点图就是大屏中居于中心位置的图,是视觉的中心,本位列举了十种焦点图样式供大家参考。 地球作为焦点图 图片来自网络 地图作为焦点图 图片来自网络 城市作为焦点图 图片来自网络 园区做焦点图 图片来自网络 建筑做焦点图 图片来自网络 生产线…...
问题 G: 老鼠和猫的交易
题目描述 小老鼠准备了M磅的猫粮,准备去和看守仓库的猫做交易,因为仓库里有小老鼠喜欢吃的五香豆。 仓库有N个房间; 第i个房间有J[i] 磅的五香豆,并且需要用F[i]磅的猫粮去交换; 老鼠不必交换该房间所有的五香豆&…...
HiveSQL——借助聚合函数与case when行转列
一、条件函数 if 条件函数 if函数是最常用到的条件函数,其写法是if(xn,a,b), xn代表判断条件,如果xn时,那么结果返回a ,否则返回b。 selectif(age < 25 or age is null, 25岁以下, 25岁以上) as age_cnt,count(1) as number from table…...
冒泡排序,判断回文,以及12-24小时制
6-7 定义函数,完成冒泡排序算法。 本题定义一个冒泡排序算法的函数,调用函数后实现数组的升序排序,其数组长度为任意长度。 函数接口定义: 在这里描述函数接口。例如: void sort(int arr[],int n); 在这里解释接口…...
【Vue】computed与watch
📝个人主页:五敷有你 🔥系列专栏:Vue⛺️稳重求进,晒太阳 计算属性 概念:基于现有的数据,计算出来新的属性,依赖的数据变化,自动重新计算 语法: 声明…...
探索设计模式的魅力:捕捉变化的风-用观察者模式提升用户体验
设计模式专栏:http://t.csdnimg.cn/U54zu 目录 一、引言 核心概念 应用场景 可以解决的问题 二、场景案例 2.1 不用设计模式实现 2.2 存在问题 2.3 使用设计模式实现 2.4 成功克服 三、工作原理 3.1 结构图和说明 3.2 工作原理详解 3.3 实现步骤 四、 优…...
SpringCloud-高级篇(十九)
我们已经学过使用 SpringAMQP去收和发消息,但是发和收消息是只是MQ最基本的功能了,在收发消息的过程中,会有很多的问题需要去解决,下面需要学习rabbitMQ的高级特性去解决 死信交换机:这个可以帮助我们实现消息的延迟的…...
Junit常用断言
0.断言简介 断言:assert Q:断言的作用 更方便的对结果进行判定 "有针对性"的if判断 针对两个变量值是否相同 使用assertEquals针对两个对象是否相同 使用assertSame针对返回值是否为True 使用assertTrue 1.断言的参数 assertXXX(”断言失败时提升的信息“&#x…...
docker 实现 mysql:8.3.0 主从复制(2024年2月13日最新版本)
环境为 CentOS 7.6, 具体操作请看MySQL主从复制01-主从复制概述及原理_哔哩哔哩_bilibili 1、配置主服务器 # 启动主服务器 docker run -p 3306:3306 --name mysql_master -e MYSQL_ROOT_PASSWORDnmnmnm67890890 -v /docker/mysql_master/conf:/etc/mysql/conf.d…...
STM32 + ESP8266,连接阿里云 上报/订阅数据
(文章正在编辑中,一点点地截图操作过程,估计要拖拉两三天) 一、烧录MQTT固件 ESP8266出厂时,默认是AT固件。连接阿里云,需要使用MQTT固件。 1、独立EPS8266模块的烧录方法 2、魔女开发板,板载…...
如何利用chatgpt提升工作效率?
在数字化和信息化的时代,人工智能技术已经深入到了我们生活的方方面面。其中,ChatGPT作为当前热门的人工智能技术,以其强大的自然语言处理能力和广泛的应用场景,正逐渐改变着我们的工作方式,为我们提高工作效率提供了全…...
MongoDB聚合:$geoNear
$geoNear根据指定的点按照距离以由近到远的顺序输出文档。 从4.2版本开始,MongoDB移除了limit和num选项以及100个文档的限制,如果要限制结果文档的数量可以使用$limit阶段。 语法 { $geoNear: { <geoNear options> } }$geoNear操作接受一个包含…...