当前位置: 首页 > ds >正文

实验1python基本网络应用

一、实验目的和任务

  1. 掌握Python网络编程的基本应用
  2. 掌握Python Socket编程方法
  3. 掌握TCP和UDP的Python编程模型

二、实验内容

1.编写Python程序获取本机的主机名称和IP地址(GUI界面)

2.编写Python程序实现UDP网络聊天(多线程GUI版)

3.(选做题)编写Python程序实现TCP文件传输

三、实验步骤

实验1.1 获取本机网络信息(GUI版)

程序结构:使用tkinter创建GUI界面,包含以下组件:

1.主机名显示标签、2.IP地址列表框、3.查询按钮

程序主要流程:

1.创建主窗口和界面布局、

2.实现"查询网络信息"按钮功能

3.使用socket.gethostname()获取主机名

4.使用socket.gethostbyname_ex()获取IP列表

5.将结果显示在GUI界面上

代码参考:  

  def get_network_info(self):"""获取网络信息并更新界面"""try:# 清空旧数据self.ip_listbox.delete(0, tk.END)# 获取主机名hostname = socket.gethostname()self.hostname_label.config(text=hostname)# 获取IP地址ip_list = socket.gethostbyname_ex(hostname)[2]for ip in ip_list:self.ip_listbox.insert(tk.END, ip)except Exception as e:tk.messagebox.showerror("错误", f"获取网络信息失败: {str(e)}")

完整python脚本如下:

import tkinter as tk
import tkinter.messagebox
import socketclass NetworkInfoApp:def __init__(self, master):self.master = mastermaster.title("本机网络信息查询")# 创建界面组件self.hostname_label = tk.Label(master, text="主机名: 未查询", font=('Arial', 12))self.hostname_label.pack(pady=10)# 网络信息显示区域info_frame = tk.Frame(master)info_frame.pack(pady=10)# IP地址列表tk.Label(info_frame, text="IP地址列表:").pack()self.ip_listbox = tk.Listbox(info_frame, width=40, height=5)self.ip_listbox.pack()# 端口信息tk.Label(info_frame, text="开放端口:").pack()self.port_listbox = tk.Listbox(info_frame, width=40, height=5)self.port_listbox.pack()# 查询按钮self.query_button = tk.Button(master, text="查询网络信息", command=self.get_network_info)self.query_button.pack(pady=10)def get_network_info(self):"""获取网络信息并更新界面"""try:# 清空旧数据self.ip_listbox.delete(0, tk.END)self.port_listbox.delete(0, tk.END)# 获取主机名hostname = socket.gethostname()self.hostname_label.config(text=f"主机名: {hostname}")# 获取IP地址ip_list = socket.gethostbyname_ex(hostname)[2]for ip in ip_list:self.ip_listbox.insert(tk.END, ip)# 获取常用端口状态common_ports = [21, 22, 80, 443, 3306, 3389]for port in common_ports:sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.settimeout(0.1)result = sock.connect_ex(('127.0.0.1', port))status = "开放" if result == 0 else "关闭"self.port_listbox.insert(tk.END, f"端口 {port}: {status}")sock.close()except Exception as e:tk.messagebox.showerror("错误", f"获取网络信息失败: {str(e)}")if __name__ == "__main__":root = tk.Tk()app = NetworkInfoApp(root)root.mainloop()

功能效果如下图所示:

实验1.2 UDP聊天程序(GUI版)

使用tkinter创建聊天界面包含以下组件:

1.本地IP和端口设置

2.目标IP和端口设

3.消息输入框和发送按钮

4.聊天记录显示区域

5.启动/停止监听按钮

主要步骤:

1.创建主窗口和界面布局、2.创建UDP socket、3.绑定指定IP和端口、4.启动接收线程、5.实现消息接收线程、6.实现消息发送功能、7.处理异常情况

代码参考:

#创建界面函数:def create_widgets(self):# 主框架main_frame = ttk.Frame(self.root, padding=10)main_frame.pack(fill=tk.BOTH, expand=True)# 地址设置addr_frame = ttk.LabelFrame(main_frame, text="网络设置", padding=10)addr_frame.grid(row=0, column=0, sticky=tk.W, pady=5)# 本地设置ttk.Label(addr_frame, text="本地IP:").grid(row=0, column=0, sticky=tk.W)self.local_ip = ttk.Entry(addr_frame, width=15)self.local_ip.insert(0, '0.0.0.0')self.local_ip.grid(row=0, column=1)ttk.Label(addr_frame, text="本地端口:").grid(row=0, column=2, padx=5)self.local_port = ttk.Entry(addr_frame, width=8)self.local_port.grid(row=0, column=3)# 目标设置ttk.Label(addr_frame, text="目标IP:").grid(row=1, column=0, sticky=tk.W, pady=5)self.target_ip = ttk.Entry(addr_frame, width=15)self.target_ip.grid(row=1, column=1)ttk.Label(addr_frame, text="目标端口:").grid(row=1, column=2)self.target_port = ttk.Entry(addr_frame, width=8)self.target_port.grid(row=1, column=3)# 消息区msg_frame = ttk.LabelFrame(main_frame, text="消息", padding=10)msg_frame.grid(row=1, column=0, sticky=tk.W, pady=5)self.msg_input = ttk.Entry(msg_frame, width=40)self.msg_input.grid(row=0, column=0)self.send_btn = ttk.Button(msg_frame, text="发送", command=self.send_message)self.send_btn.grid(row=0, column=1, padx=5)# 聊天记录self.chat_history = scrolledtext.ScrolledText(main_frame, width=50, height=15)self.chat_history.grid(row=2, column=0)# 控制按钮self.start_btn = ttk.Button(main_frame, text="启动监听", command=self.toggle_server)self.start_btn.grid(row=3, column=0, pady=10)启动\关闭服务器函数,绑定在启动监听按钮:def toggle_server(self):if not self.running:try:self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)self.socket.bind((self.local_ip.get(), int(self.local_port.get())))self.running = Trueself.start_btn.config(text="停止监听")threading.Thread(target=self.recv_thread, daemon=True).start()except Exception as e:messagebox.showerror("错误", f"启动失败: {str(e)}")else:self.running = Falseself.socket.close()self.start_btn.config(text="启动监听")#消息接收线程,在启动监听后开始。def recv_thread(self):"""接收消息线程"""while self.running:try:data, addr = self.socket.recvfrom(1024)msg = f"[来自 {addr[0]}:{addr[1]}]: {data.decode()}\n"self.chat_history.insert(tk.END, msg)except:break#发送消息函数,绑定在发送按钮:def send_message(self):try:msg = self.msg_input.get()if not msg:returntarget = (self.target_ip.get(), int(self.target_port.get()))self.socket.sendto(msg.encode(), target)self.chat_history.insert(tk.END, f"[我]: {msg}\n")self.msg_input.delete(0, tk.END)except Exception as e:messagebox.showerror("错误", f"发送失败: {str(e)}")

完整python脚本如下:

import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox
import socket
import threadingclass UDPChatApp:def __init__(self, root):self.root = rootself.root.title("UDP网络聊天程序")self.running = Falseself.socket = Noneself.create_widgets()def create_widgets(self):# 主框架main_frame = ttk.Frame(self.root, padding=10)main_frame.pack(fill=tk.BOTH, expand=True)# 地址设置addr_frame = ttk.LabelFrame(main_frame, text="网络设置", padding=10)addr_frame.grid(row=0, column=0, sticky=tk.W, pady=5)# 本地设置ttk.Label(addr_frame, text="本地IP:").grid(row=0, column=0, sticky=tk.W)self.local_ip = ttk.Entry(addr_frame, width=15)self.local_ip.insert(0, '0.0.0.0')self.local_ip.grid(row=0, column=1)ttk.Label(addr_frame, text="本地端口:").grid(row=0, column=2, padx=5)self.local_port = ttk.Entry(addr_frame, width=8)self.local_port.grid(row=0, column=3)# 目标设置ttk.Label(addr_frame, text="目标IP:").grid(row=1, column=0, sticky=tk.W, pady=5)self.target_ip = ttk.Entry(addr_frame, width=15)self.target_ip.grid(row=1, column=1)ttk.Label(addr_frame, text="目标端口:").grid(row=1, column=2)self.target_port = ttk.Entry(addr_frame, width=8)self.target_port.grid(row=1, column=3)# 消息区msg_frame = ttk.LabelFrame(main_frame, text="消息", padding=10)msg_frame.grid(row=1, column=0, sticky=tk.W, pady=5)self.msg_input = ttk.Entry(msg_frame, width=40)self.msg_input.grid(row=0, column=0)self.send_btn = ttk.Button(msg_frame, text="发送", command=self.send_message)self.send_btn.grid(row=0, column=1, padx=5)# 聊天记录self.chat_history = scrolledtext.ScrolledText(main_frame, width=50, height=15)self.chat_history.grid(row=2, column=0)# 控制按钮self.start_btn = ttk.Button(main_frame, text="启动监听", command=self.toggle_server)self.start_btn.grid(row=3, column=0, pady=10)def toggle_server(self):if not self.running:try:self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)self.socket.bind((self.local_ip.get(), int(self.local_port.get())))self.running = Trueself.start_btn.config(text="停止监听")threading.Thread(target=self.recv_thread, daemon=True).start()except Exception as e:messagebox.showerror("错误", f"启动失败: {str(e)}")else:self.running = Falseif self.socket:self.socket.close()self.start_btn.config(text="启动监听")def recv_thread(self):"""接收消息线程"""while self.running:try:data, addr = self.socket.recvfrom(1024)msg = f"[来自 {addr[0]}:{addr[1]}]: {data.decode()}\n"self.chat_history.insert(tk.END, msg)except:breakdef send_message(self):try:msg = self.msg_input.get()if not msg:returntarget = (self.target_ip.get(), int(self.target_port.get()))self.socket.sendto(msg.encode(), target)self.chat_history.insert(tk.END, f"[我]: {msg}\n")self.msg_input.delete(0, tk.END)except Exception as e:messagebox.showerror("错误", f"发送失败: {str(e)}")if __name__ == "__main__":root = tk.Tk()app = UDPChatApp(root)root.mainloop()

功能效果如下图所示:

四、思考问题

1.Python中如何获取本机的主机名?

答:在Python中,可以使用socket模块的gethostname()函数来获取本机的主机名。

2.在实验1.1中,我们使用了哪个函数来获取主机名?哪个函数来获取IP地址列表?

答:获取主机名有socket.gethostname(),获取IP地址列表有socket.gethostbyname_ex(hostname)
其中,hostname是通过gethostname()获取的主机名。gethostbyname_ex()返回一个包含主机名、别名列表和IP地址列表的元组。

3.UDP和TCP有什么区别?

答:

特性UDP (用户数据报协议)TCP (传输控制协议)
连接方式无连接面向连接
可靠性不可靠,不保证数据顺序或送达可靠,保证数据顺序和送达
速度快,开销小较慢,开销大
流量控制
拥塞控制
适用场景实时应用(视频、语音、游戏)需要可靠传输的应用(文件传输、网页浏览)

4.为什么实验1.2的程序要使用多线程?如果不使用多线程,直接在主线程中接收消息会有什么问题?

答:两种原因

        使用多线程的原因
        聊天程序需要同时处理发送和接收消息的任务。如果只用单线程,程序会在等待接收消息时阻塞,无法同时发送消息,用户体验差。

        不用多线程的问题
        主线程会因等待接收消息而被阻塞,导致程序无法及时响应用户输入或其他任务,失去交互性。

5. 在实验1.2中,我们使用了UDP协议,如果改用TCP实现聊天程序,代码会有哪些关键变化?

答:关键变化

        建立连接:TCP需要先建立连接(socket.connect()或socket.listen()和socket.accept())。
        数据传输:TCP使用send()和recv(),而UDP使用sendto()和recvfrom()。
        可靠性处理:TCP无需额外处理丢包或乱序,而UDP需要手动处理。
        多线程/多进程:TCP可能需要更复杂的线程管理(如为每个连接创建线程)。

6. UDP是无连接的,如果网络丢包,程序会怎样?如何检测消息是否送达?

答:丢包的影响:

        程序不会自动重传或报错,数据可能丢失或乱序,需要应用层处理。

检测消息送达的方法:

        应用层确认机制:接收方收到消息后发送确认(ACK),发送方等待ACK超时则重传。
        超时重传:发送方设置超时时间,未收到ACK则重发。
        序列号:为消息添加序列号,接收方检查是否连续。

http://www.xdnf.cn/news/1311.html

相关文章:

  • 为TA开发人员介绍具有最新改进的Kinibi-610a
  • 【Vue3 / TypeScript】 项目兼容低版本浏览器的全面指南
  • 【MySQL】数据库基础
  • 从马拉松到格斗大赛:人形机器人撕开的万亿市场,正在改写AI规则
  • STM32单片机入门学习——第45节: [13-2] 修改频主睡眠模式停止模式待机模式
  • G1 人形机器人硬件构成与接口
  • 图像挖掘课程笔记-第一章:了解机器视觉
  • 【TeamFlow】4.3.2 细化时间单位
  • 设备预测性维护系统部署成本:技术架构与成本优化策略解析
  • Linux——基于socket编程实现简单的Tcp通信
  • Size of map written was 1, but number of entries written was 0. 异常分析
  • 进阶篇 第 7 篇 (终章):融会贯通 - 多变量、模型选择与未来之路
  • 数据可视化--数据探索性分析
  • 数据库MySQL学习——day1(创建表与数据类型)
  • win10中打开python的交互模式
  • Ubuntu 22.04安装IGH
  • CRM系统的功能有哪些?CRM系统功能指南
  • RenderDoc 使用介绍
  • STL C++详解——priority_queue的使用和模拟实现 堆的使用
  • 高新技术申报有哪些潜在风险?如何避免?
  • AI 模型可靠性危机:DeepSeek 输出异常的技术归因与防范实践
  • 算力网络有关论文自用笔记(2)
  • L1-5、Prompt 写作中的常见误区
  • 公路路面病害检测
  • 【AI】SpringAI 第五弹:接入千帆大模型
  • 通过AI工具或模型创建PPT的不同方式详解,结合 Assistants API、DALL·E 3 等工具的功能对比及表格总结
  • 用红黑树封装出set和map
  • Pandas与NumPy高效结合使用指南
  • 利用内联注解析释差异构造多语言sql注入 -- b01lers CTF defense-in-depth
  • Linux从入门到荒废-查找文件中重复的数据