python之路_基于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期部分视频day011.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]的一条消息:33[1;44m%s33[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]的一条消息:33[1;44m%s33[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]的一条消息:33[1;44m%s33[0m' %(addr[0],addr[1],back_msg.decode('utf-8')))

udp_client_socket.close()
原文地址:https://www.cnblogs.com/seven-007/p/7603038.html