• py6.6


    #文件的上传和下载:
    #自定义一个字典,让用户选择功能(上传/下载)。将要上传的文件路径传入,找到文件名,打开文件,计算文件大小,
    #将功能、文件名、文件大小定义成一个字典,通过stuct模块和json模块固定字典的长度为4并序列化,以便防止发送
    #时与后面要发送的文件内容出现黏包现象。通过循环将文件按照固定的大小(1024)分次发送到服务端。服务端也根据收到
    #的文件大小来分次接收。
    #struct模块
    # import struct
    # #
    # r = struct.pack('i',10) #将10变成一个固定的长度4的字符串
    # print(len(r))
    # print(r)
    # print(struct.unpack('i',r))#解开,得到的是一个元祖形式,原数值在元祖的第0个元素。
    
    # import json
    # dic = {'a': '1'}
    # r = json.dumps(dic)
    # print(json.loads(r))
    
    
    
    
    server:
    
    import socket
    import struct
    import json
    
    sk = socket.socket()
    
    sk.bind(('127.0.0.1',8080))
    
    sk.listen(5)
    
    conn , addr = sk.accept()
    
    r  = conn.recv(4) #接收从客户端处已经被struct模块将原字典长度转换成固定长度的bytes(长度为4)
    len_dic = struct.unpack('i',r)[0]#将这个bytes解开,变成一个元祖,要的是第一个元素-->原字典的长度。
    # print(len_dic)
    str_dic = conn.recv(len_dic).decode('utf-8')#根据原字典的长度来接收被序列化了字典
    # print(str_dic)
    str_dic = json.loads(str_dic)#将字典反序列化
    
    
    if str_dic['opt'] == 'upload':
        name = 'new_' + str_dic['name']#防止重名,加一个前缀。
        with open(name,mode='wb') as f:#以bytes类型直接写进文件。
            file_size = str_dic['file_size']#获取传入文件的大小。
            while file_size:
                content = conn.recv(1024)#分次接收。
                f.write(content)         #接收一次写入一次。
                file_size -= len(content)#剩余的大小。
    
    conn.close()#TCP协议两个套接字。
    sk.close()
    
    client:
    
    import socket
    import os
    import json
    import struct
    
    sk = socket.socket()
    
    sk.connect(('127.0.0.1',8080))
    
    dic_c = {'1':'upload',
               '2':'download'
               }               #定义一个供用户选择的字典
    
    while 1:
        num = input('请输入序号').strip()
        if num == '1':
            for k,v in dic_c.items():#将字典展示出来。
                print(k,':',v)
            path = input('请输入一个文件路径').strip()
            name = os.path.basename(path) #获取文件名,传入服务端,写入文件用。
            file_size = os.path.getsize(path)#获取文件大小,用来循环并分次传输。
            dic = {'opt': dic_c[num],'name':name,'file_size':file_size}#将功能、文件名、大小作为字典传入服务端。
            str_dic = json.dumps(dic) #将字典序列化,变成字符串,才能传输。
            len_dic = len(str_dic)  #计算序列化后的字典的长度。
            r = struct.pack('i',len_dic)#通过序列号后的字典的长度将其变成长度为固定4位的bytes.
            sk.send(r)                  #将固定后的bytes传入服务端。
            sk.send(str_dic.encode('utf-8'))#另一端已经解出了序列化后字典的长度,发送即可。
            with open(name,mode='rb') as f:#以bytes类型读取,就不用转码了。
                while file_size:
                    content = f.read(1024)#分次读取
                    sk.send(content)      #分次传输,直到传到没有为止。另一端也是与此同样来分次接收
                    file_size -= len(content)
            break
    sk.close()
    文件上传
    #执行系统命令:subprocess模块
    # import subprocess
    #
    # res = subprocess.Popen('dir',shell=True,#告诉系统把'dir'当做系统命令来执行。
    #                        stdout=subprocess.PIPE,#接收正确的结果
    #                        stderr=subprocess.PIPE #接收错误的结果
    #                        )
    #
    # print(res.stdout.read().decode('gbk'))#windows默认编码gbk,按照gbk解码读取。
    # print('stderr:'+res.stderr.read().decode('gbk'))#没有错误结果,显示空。
    #黏包现象:1.发送端与接收端的数据不对等,接收端能接收的字节<发送的数据,接收到一部分数据,下次再执行命令接收的时候再从上一次
    #开始。接收端能接收的字节>发送的数据,如果数据较小,nagle算法会将数据较小及时间间隔较短的数据黏包,合并到一起一同接收。
    #如果没有合理的拆包机制,则造成了无法拆分,出现黏包现象。
    #tcp是字节流的形式。不能有空消息,如果有空消息,流中就会出现错误。造成无法发送。需要有空消息处理机制。
    #udp是数据报形式,可以有空消息。
    #tcp有黏包现象,udp没有。udp是一个sendto对应一个recvfrom,一条消息对应一条消息,如果接收的字节数不够,那其余的数据
    #就会丢失。所以不可靠。不会黏包。
    黏包
    #自己创建一个模块,通过调用此模块,省略一些编码解码的步骤。
    # from socket import *
    #
    # class My_socket(socket): #以socket作为父类。
    #     def __init__(self,coding = 'utf-8'):#编码为默认关键字参数。
    #         self.coding = coding
    #         super(My_socket, self).__init__(type=SOCK_DGRAM) #没有socket.
    #
    #     def my_recv(self,num):  #传进来接收的字节数。如1024
    #         msg_r ,addr = self.recvfrom(num)
    #         return msg_r.decode(self.coding),addr #返回编好码的内容,按照传进来的或默认的编码方式。
    #
    #     def my_send(self,msg_s,addr):
    #         return self.sendto(msg_s.encode(self.coding),addr)#返回编好码的要发送的内容。
    
    server:
    from 练习 import My_socket
    
    sk = My_socket() #实例化一个套接字对象。
    
    sk.bind(('127.0.0.1',8090))#正常绑定
    
    while 1:
        msg_r , addr = sk.my_recv(1024) #调用类中接收方法。
        print(msg_r)            #不需要做解码动作。
    
        msg_s = input('>>>')
        sk.my_send(msg_s,addr)  #调用发送函数。不需要编码。
    
    sk.close()
    
    client:
    
    from 练习 import My_socket
    
    sk = My_socket()
    
    while 1:
        msg_s = input('>>>')
        sk.my_send(msg_s,('127.0.0.1',8090))
    
        msg_r ,addr = sk.my_recv(1024)
        print(msg_r)
    
    sk.close()
    自定义socket
    #编码流程:
    #    TCP                                       udp
    #     s           c                             s                  c
    # 创建套接字                               创建套接字
    # 绑定套接字                               绑定套接字
    # 监听
    # 等待接收      连接
    # 发送/接收                               先接收/再发送
    # 关闭c套接字
    # 关闭s套接字    关闭s套接字              关闭套接字           关闭套接字
    TCP/UDP编码流程
  • 相关阅读:
    用iText5-2-其他类型PDF
    用iText5-1-生成PDF
    UML介绍-2.3-StarUML的时序图
    UML介绍-2.2-StarUML的类图
    OOAD 面向对象的分析与设计
    激励自己的话
    UML工具-1-StarUML下载及破解
    A1002 字符串长度
    A1001 整除问题
    剑桥雅思写作高分范文ESSAY10
  • 原文地址:https://www.cnblogs.com/liujjpeipei/p/9147241.html
Copyright © 2020-2023  润新知