python学习_day31_基于udp协议编程
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python学习_day31_基于udp协议编程相关的知识,希望对你有一定的参考价值。
一、作业解析
基于tcp文件流协议执行客户端的下载命令。
服务端:
from socket import * import json import struct import os import hashlib def get(filename,conn): header_dic={ ‘filename‘:os.path.basename(filename), #获得去除路径的纯文件名 ‘data_size‘:os.path.getsize(filename) #获得文件的字节大小 } header_json=json.dumps(header_dic) #将报头字典序列化 header_bytes=header_json.encode(‘utf-8‘) #将序列化的报头字典转为字节 header_size=struct.pack(‘i‘,len(header_bytes)) #将字节报头长度打包成固定的字节数4 conn.send(header_size) #发送打包后固定字节数 conn.send(header_bytes) #发送报头字典的字节形式 m=hashlib.md5() with open(filename,‘rb‘) as f: for line in f: m.update(line) #逐行进行摘要算法 conn.send(line) #逐行发送文件 conn.send(m.hexdigest().encode(‘utf-8‘)) #将文件的摘要算法结果发送 sever=socket(AF_INET,SOCK_STREAM) sever.bind((‘127.0.0.1‘,8090)) sever.listen(5) while True: conn,addr=sever.accept() while True: obj=conn.recv(1024).strip() if not obj:break cmd,filename=obj.decode(‘utf-8‘).split() if cmd==‘get‘: get(filename,conn) conn.close() sever.close()
客户端:
from socket import * import json import struct import os import hashlib download_dir=r‘D:\\‘ client=socket(AF_INET,SOCK_STREAM) client.connect((‘127.0.0.1‘,8090)) while True: cmd=input(">>>").strip() if not cmd:continue client.send(cmd.encode(‘utf-8‘)) #发送指令,如:get D:\\全栈5期部分视频\day01\1.mp4 obj=client.recv(4) #接收打包后固定长度字节 head_size=struct.unpack(‘i‘,obj)[0] #解包,得到报头字典的大小 head_bytes=client.recv(head_size) #根据报头大小收取报头字节 head_json=head_bytes.decode(‘utf-8‘) #将报头字节转为序列化字典 head_dic=json.loads(head_json) #将序列化字典反序列化 filename=head_dic[‘filename‘] #取不包含路径的文件名 abs_path = r‘%s\%s‘ % (download_dir, filename) #定义下载文件储存路径 data_size=head_dic[‘data_size‘] recv_size=0 with open(abs_path,‘wb‘) as f: m = hashlib.md5() while recv_size<data_size: line=client.recv(1024) #循环收取文件 f.write(line) #将收取的文件写进文件 recv_size+=len(line) m.update(line) client_md5=m.hexdigest() sever_mad5=client.recv(1024).decode(‘utf-8‘) if client_md5!=sever_mad5: os.remove(abs_path) print(‘下载错误,请重新下载‘)
二、基于udp套接字
udp是无链接的,先启动哪一端都不会报错。UDP(user datagram protocol,用户数据报协议)是无连接的,面向消息的,提供高效率服务。不会使用块的合并优化算法,, 由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。 即面向消息的通信是有消息保护边界的。不会发生粘包现象。
1、简单实例
服务端:
from socket import * sever=socket(AF_INET,SOCK_DGRAM) #创建服务器套接字 sever.bind((‘127.0.0.1‘,8090)) #绑定服务器套接字 while True: #服务器循环 data,addr_client=sever.recvfrom(1024) #接收对话 print(data.decode(‘utf-8‘)) msg=input(‘>>>‘).strip() if msg==‘q‘:break sever.sendto(msg.encode(‘utf-8‘),addr_client) #发送对话 sever.close() #关闭服务器套接字
客户端:
from socket import * client=socket(AF_INET,SOCK_DGRAM) #创建客户套接字 while True: #通讯循环 msg=input(‘>>>‘).strip() if msg == ‘q‘: break client.sendto(msg.encode(‘utf-8‘),(‘127.0.0.1‘,8090)) #发送消息 data,addr_sever=client.recvfrom(1024) #接收消息 print(data.decode(‘utf-8‘)) client.close() #关闭客户套接字
2、qq聊天
由于udp无连接,所以可以同时多个客户端去跟服务端通信
服务端:
import socket ip_port=(‘127.0.0.1‘,8081) sever=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) sever.bind(ip_port) while True: qq_msg,addr=sever.recvfrom(1024) print(‘来自[%s:%s]的一条消息:\033[1;44m%s\033[0m‘ %(addr[0],addr[1],qq_msg.decode(‘utf-8‘))) back_msg=input(‘回复消息: ‘).strip() sever.sendto(back_msg.encode(‘utf-8‘),addr)
客户1:
import socket client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) qq_name_dic={ ‘狗哥alex‘:(‘127.0.0.1‘,8081), ‘瞎驴‘:(‘127.0.0.1‘,8081), ‘一棵树‘:(‘127.0.0.1‘,8081), ‘武大郎‘:(‘127.0.0.1‘,8081), } while True: qq_name=input(‘请选择聊天对象: ‘).strip() while True: msg=input(‘请输入消息,回车发送: ‘).strip() if msg == ‘quit‘:break if not msg or not qq_name or qq_name not in qq_name_dic:continue client.sendto(msg.encode(‘utf-8‘),qq_name_dic[qq_name]) back_msg,addr=client.recvfrom(1024) print(‘来自[%s:%s]的一条消息:\033[1;44m%s\033[0m‘ %(addr[0],addr[1],back_msg.decode(‘utf-8‘))) udp_client_socket.close()
客户2:
import socket client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) qq_name_dic={ ‘狗哥alex‘:(‘127.0.0.1‘,8081), ‘瞎驴‘:(‘127.0.0.1‘,8081), ‘一棵树‘:(‘127.0.0.1‘,8081), ‘武大郎‘:(‘127.0.0.1‘,8081), } while True: qq_name=input(‘请选择聊天对象: ‘).strip() while True: msg=input(‘请输入消息,回车发送: ‘).strip() if msg == ‘quit‘:break if not msg or not qq_name or qq_name not in qq_name_dic:continue client.sendto(msg.encode(‘utf-8‘),qq_name_dic[qq_name]) back_msg,addr=client.recvfrom(1024) print(‘来自[%s:%s]的一条消息:\033[1;44m%s\033[0m‘ %(addr[0],addr[1],back_msg.decode(‘utf-8‘))) udp_client_socket.close()
以上是关于python学习_day31_基于udp协议编程的主要内容,如果未能解决你的问题,请参考以下文章
Python100天学习笔记Day20 迭代器与生成器及 并发编程