zoukankan      html  css  js  c++  java
  • 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()
  • 相关阅读:
    分享到新浪微博js
    好的读书网站发现、翻译 阅读中文之外的互联网精华
    ps字体下载素材网址
    如何使用HTML5,CSS3和PHP创建一个联系表格
    css3 精品网站
    IE6解决无法实现position:fixed浮动层固定在滚动页面(无抖动)
    nginx笔记
    给力shell命令
    常用v_视图
    关于获取运营商的IP地址
  • 原文地址:https://www.cnblogs.com/seven-007/p/7603038.html
Copyright © 2011-2022 走看看