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=rD:\\
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协议编程的主要内容,如果未能解决你的问题,请参考以下文章

Python学习笔记__16.3章 UDP编程

python学习_day30_基于tcp协议的粘包现象

Python网络_UDP编程

Python100天学习笔记Day20 迭代器与生成器及 并发编程

Python100天学习笔记Day20 迭代器与生成器及 并发编程

day20-网络编程