zoukankan      html  css  js  c++  java
  • 通过非IO阻塞模型实现ftp并发的小代码

      1 import os
      2 import time
      3 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
      4 import socket
      5 import selectors
      6 
      7 class selectFtpServer:#服务端创建一个类
      8 
      9     def __init__(self):#对象初始化的定义
     10         self.dic = {}#定义一个空字典
     11         self.hasReceived=0#定义一个接受值的大小
     12         self.sel = selectors.DefaultSelector()#实例化一个selectors对象
     13         self.create_socket()#调用建立连接函数
     14         self.handle()#调用handle函数。
     15 
     16     def create_socket(self):
     17         server = socket.socket()
     18         server.bind(("127.0.0.1",8885))
     19         server.listen(5)
     20         server.setblocking(False)#非IO阻塞模型
     21         self.sel.register(server, selectors.EVENT_READ, self.accept)
     22         #注册一个监听对象,如果server变化执行accept函数。
     23         print("服务端已开启,等待用户连接...")
     24 
     25     def handle(self):
     26         while True:
     27             events = self.sel.select()#监听,将变化的内容赋值
     28             for key, mask in events:#循环发生变化的对象
     29                 callback = key.data#将该对象的方法赋值
     30                 callback(key.fileobj, mask)#执行这个方法并传参
     31 
     32     def accept(self,sock, mask):
     33         conn, addr = sock.accept()
     34         print("from %s %s connected"%addr)
     35         self.sel.register(conn, selectors.EVENT_READ, self.read)
     36         #注册conn,如果发生变化执行read函数
     37         self.dic[conn] = {}#将conn传入字典,将一个空字典作为值
     38 
     39     def read(self, conn, mask):#read函数具体执行上传和下载的功能
     40         try:
     41             if not self.dic[conn] :#如果这个conn不在字典里,说明这是第一次接收到该客户端消息
     42                 data = conn.recv(1024)#接收1024的内容
     43                 cmd,filename,filesize = str(data, encoding='utf-8').split('|')#将内容以管道符分割,分别赋值
     44                 self.dic={conn:{"cmd": cmd, "filename": filename,"filesize": int(filesize)}}#将取到的内容放到字典里
     45                 if cmd == 'put':#如果cmd为put
     46                     conn.send(bytes("OK",encoding='utf8'))#回一个返回值
     47                 if self.dic[conn]['cmd'] == 'get':#如果传来的命令是get
     48                     file = os.path.join(BASE_DIR,"download",filename)#拼接文件路径
     49                     if os.path.exists(file):#如果文件存在
     50                         fileSize = os.path.getsize(file)#文件大小等于filesize
     51                         send_info = '%s|%s'%('YES',fileSize)#将文件大小等放入事先定制好的格式当中。
     52                         conn.send(bytes(send_info, encoding='utf8'))#发送这个文件信息
     53                     else:
     54                         send_info = '%s|%s'%('NO',0)#如果文件不存在,将消息赋值
     55                         conn.send(bytes(send_info, encoding='utf8'))#发送
     56             else:
     57                 if self.dic[conn].get('cmd',None):#如果conn在字典里,取出cmd,如果没有则返回None
     58                     cmd=self.dic[conn].get('cmd')#将get到的内容赋值给cmd
     59                     if hasattr(self, cmd):#如果cmd这个函数存在
     60                         func = getattr(self,cmd)#获取这个函数并赋值
     61                         func(conn)#加上参数,调用执行
     62                     else:
     63                         print("error cmd!")#如果这个函数不存在,打印error
     64                         conn.close()#关闭连接
     65                 else:
     66                     print("error cmd!")
     67                     conn.close()
     68 
     69         except Exception as e:#异常处理
     70             print('error', e)
     71             self.sel.unregister(conn)#解除注册
     72             conn.close()
     73 
     74     def put(self, conn):#上传
     75 
     76         fileName = self.dic[conn]['filename']#字典的文件名赋值
     77         fileSize = self.dic[conn]['filesize']#字典的文件大小赋值
     78         path = os.path.join(BASE_DIR,"upload",fileName)#文件拼接
     79         recv_data = conn.recv(1024)#收1024
     80         self.hasReceived += len(recv_data)#已经收到的
     81 
     82         with open(path, 'ab') as f:#做收文件内容的操作
     83             f.write(recv_data)
     84         if fileSize == self.hasReceived:#如果收到的大小等于实际大小
     85             if conn in self.dic.keys():#如果这个conn在字典中存在则清空
     86                 self.dic[conn] = {}
     87             print("%s上传完毕!"%fileName)
     88 
     89     def get(self,conn):#下载
     90         filename = self.dic[conn]['filename']#取文件名
     91         path = os.path.join(BASE_DIR,"download",filename)#拼接路径
     92         if str(conn.recv(1024), 'utf-8') == "second_active":#收文件
     93             with open(path, 'rb') as f:
     94                 for line in f:
     95                     conn.send(line)
     96             self.dic[conn] = {}#请空字典
     97             print('文件下载完毕!')
     98 
     99 
    100 if __name__ == '__main__':
    101 
    102     selectFtpServer()

    上面是server端代码,主要就是通过socket和selectors来实现,可以多加练习。

     1 import socket
     2 import os,sys
     3 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
     4 
     5 class selectFtpClient:
     6 
     7     def __init__(self):
     8         self.args=sys.argv
     9         if len(self.args)>1:
    10             self.port=(self.args[1],int(self.args[2]))#如果运行的时候后面有参数
    11         else:
    12             self.port=("127.0.0.1",8885)#默认
    13         self.create_socket()#创建连接函数
    14         self.command_fanout()#通过反射获取函数的函数
    15 
    16     def create_socket(self):
    17         try:
    18             self.sk = socket.socket()
    19             self.sk.connect(self.port)
    20             print('连接FTP服务器成功!')
    21         except Exception as e:
    22             print("error: ",e)
    23 
    24     def command_fanout(self):
    25         while True:
    26             cmd = input('>>>').strip()
    27             if cmd == 'exit()':
    28                 break
    29             cmd,file = cmd.split()
    30             if hasattr(self, cmd):
    31                 func = getattr(self, cmd)
    32                 func(cmd,file)
    33             else:
    34                 print('调用错误!')
    35 
    36     def put(self,cmd,file):
    37 
    38         if os.path.isfile(file):
    39             fileName= os.path.basename(file)
    40             fileSize = os.path.getsize(file)
    41             fileInfo ='%s|%s|%s'%(cmd,fileName,fileSize)
    42             self.sk.send(bytes(fileInfo, encoding='utf8'))
    43             recvStatus = self.sk.recv(1024)
    44             print('recvStatus', recvStatus)
    45             hasSend = 0
    46             if str(recvStatus, encoding='utf8') == "OK":
    47                 with open(file, 'rb') as f:
    48                     while fileSize > hasSend :
    49                         contant = f.read(1024)
    50                         recv_size = len(contant)
    51                         self.sk.send(contant)
    52                         hasSend += recv_size
    53                         s=str(int(hasSend/fileSize*100))+"%"
    54                         print("正在上传文件:"+fileName+"   已经上传:"+s)
    55                 print('%s文件上传完毕' % (fileName,))
    56         else:
    57             print('文件不存在')
    58 
    59 
    60 if __name__ == '__main__':
    61 
    62     selectFtpClient()

    上面为客户端代码

  • 相关阅读:
    手动配置linux(centos)的IP地址
    linux(centos)上配置nginx、mysql、phpfpm开机启动
    visual studio 2022 下载地址
    自己动手开发编译器(五)miniSharp语言的词法分析器
    自己动手开发编译器(一)编译器的模块化工程
    自己动手开发编译器(二)正则语言和正则表达式
    趣味问题:你能用Reflection.Emit生成这段代码吗?
    自己动手开发编译器(零)序言
    自己动手开发编译器特别篇——用词法分析器解决背诵圣经问题
    自己动手开发编译器(三)有穷自动机
  • 原文地址:https://www.cnblogs.com/ArmoredTitan/p/7250747.html
Copyright © 2011-2022 走看看