完整代码链接:https://download.csdn.net/download/qq_34162147/54904655
本章节是续前篇(界面篇)。如未搭建界面,请查阅以下链接。
串网直通车——界面篇(Python+Tkinter)_不尽之野火-CSDN博客
本章节主要是实现网口的UDP功能,实现网口收发数据。类似网络调试助手。
1、打开网口
Python使用网口功能以及线程功能,需要在开头引入。结合前篇(界面篇),需要在开头引入全局变量。
import socket #网口
import threading #线程
global udp_socket
global opposite_addr
global net_text
net_state=0
global trans_uc
将以下代码替换到界面篇的net_ctrl函数。整体替换。
这个函数中nn_var,lip_var,lp_var,oip_var,op_var,nl_var,p0,p1都是通过按钮操作传递过来,读取下拉菜单的值。
nn_var是按钮控件名
lip_var是本地IP地址
lp_var是本地端口号
oip_var是远程IP地址
op_var是远程端口号
nl_var是指示灯控件
p0是红灯图片
p1是绿灯图片
函数中,recv_net_data是用来定义接收线程。接收函数是thread_net_recv,后续有讲解。创建线程是为了实现接收一直起作用,程序并与界面显示并行运行。
代码经过优化,经测试达到0错误。代码中多次使用if和else pass组合。是因为参考其他程序时,发现有错误,无法正常停止网口,端口号一直被占用。而且在else之后绑定网口的udp_socket无法继续使用。如有大神能够知道原因,请在评论区告知,在此感谢!
# 网口打开关闭函数
def net_ctrl(nn_var,lip_var,lp_var,oip_var,op_var,nl_var,p0,p1):
global udp_socket
global opposite_addr
global net_text
global net_state
if nn_var.get() == "打开网口":
# 创建一个UDP套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 本地ip地址和端口号,这是一个元组,其中ip地址是字符串,端口号是数字
local_addr = (lip_var, int(lp_var))
# 绑定本地的相关信息,如果不绑定,则系统会随机分配一个端口号
udp_socket.bind(local_addr)
# 远程ip地址和端口号,这是一个元组,其中ip地址是字符串,端口号是数字
opposite_addr = (oip_var, int(op_var))
net_state=1
net_text.delete(1.0,END)
nl_var.configure(image=p1)
recv_net_data = threading.Thread(target=thread_net_recv)#创建接收线程
recv_net_data.start()
else :
pass
if nn_var.get() == "关闭网口" :
udp_socket.close()
net_state=0
nn_var.set("打开网口")
nl_var.configure(image=p0)
else:
pass
if (net_state==1) :
nn_var.set("关闭网口")
nl_var.configure(image=p1)
else:
pass
2、接收
接收函数整体添加即可。这部分对应打开网口的thread_net_recv函数。
代码中net_text.see(END),see是用于ScrolledText滚动条文本框控件的光标移动,使得滚动条随着接收数据的增多而移动至最后。此部分结合界面篇的带滚动条文本框部分。
代码中使用了try和except Exception:break的组合,作用在于接收时,防止接收函数recvfrom()导致出错。出错时会有退出机制。其他网上代码存在此部分不完善的地方。这部分导致停止运行时无法正常停止。必须强制关闭运行进程。
代码中“停止接收线程”备注那部分,作用是点击按钮关闭时,能够跳出线程,并终止。因为接收代码运行时,一直在while循环。其他网上代码存在此部分不完善的地方。必须强制关闭运行进程,否则网口端口号一直出错而占用。
代码中的decode是解码。
此部分代码提到的net_send函数,后续会讲解到。只测试接收时,可以先屏蔽。
特别注意:此部分代码测试时,不能直接点击窗口右上角关闭,必须优先点击关闭网口按钮,再关闭窗口。
# 网口数据接收线程
def thread_net_recv():
global net_text
global net_state
global trans_uc
while True:
try:
read_net = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数
trans_uc=read_net[0].decode("utf-8")
net_text.insert(END,trans_uc)
net_text.insert(END,'\n')
net_text.see(END)#滚动条移动到最新输入位置
net_send('I have received your data')
print(read_net,)
print("UDP 接收到的数据:%s" % trans_uc)
# addr_ip,addr_port=read_net[1]
# print("接收到的对方IP地址:%s" % addr_ip)
# print("接收到的对方端口:%s" % addr_port)
# net_send('OK')
except Exception:
break
插节
如果程序一直运行,不知道什么错误,如图所示,可以强制停止。我用的是VScode+python3.8。
3、发送
这部分的代码直接添加即可。此部分结合接收函数使用测试。
代码中encode是编码。ns_var是字符串,目的地址opposite_addr(IP+端口号)引用之前变量,只引用不改变参数,无需使用global。
def net_send(ns_var):
udp_socket.sendto(ns_var.encode('utf-8'), opposite_addr)
4、测试
可用网络调试助手配合从测试。测试效果如图所示。
5、拓展
在学习过程,参考了不少资料,也填了不少坑。在此感谢各位前辈们的付出。经过整理筛选后,同样将有用的分享给大家!
python socket recv超时_如何用python实现接收UDP方式的网络通信数据_weixin_39999025的博客-CSDN博客
Python网络通信(1)— UDP通信_Willliam_william的博客-CSDN博客
Python网络通信
https://so.csdn.net/so/search?q=Python%E7%BD%91%E7%BB%9C%E9%80%9A%E4%BF%A1&t=blog&u=qq_38113006