zoukankan      html  css  js  c++  java
  • Python之FTP实现

    Python之FTP实现

       上传下载:

      1 import socket
      2 import struct
      3 import json
      4 import subprocess
      5 import os
      6 
      7 class MYTCPServer:
      8     address_family = socket.AF_INET
      9 
     10     socket_type = socket.SOCK_STREAM
     11 
     12     allow_reuse_address = False
     13 
     14     max_packet_size = 8192
     15 
     16     coding='utf-8'
     17 
     18     request_queue_size = 5
     19 
     20     server_dir='file_upload'
     21 
     22     def __init__(self, server_address, bind_and_activate=True):
     23         """Constructor.  May be extended, do not override."""
     24         self.server_address=server_address
     25         self.socket = socket.socket(self.address_family,
     26                                     self.socket_type)
     27         if bind_and_activate:
     28             try:
     29                 self.server_bind()
     30                 self.server_activate()
     31             except:
     32                 self.server_close()
     33                 raise
     34 
     35     def server_bind(self):
     36         """Called by constructor to bind the socket.
     37         """
     38         if self.allow_reuse_address:
     39             self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     40         self.socket.bind(self.server_address)
     41         self.server_address = self.socket.getsockname()
     42 
     43     def server_activate(self):
     44         """Called by constructor to activate the server.
     45         """
     46         self.socket.listen(self.request_queue_size)
     47 
     48     def server_close(self):
     49         """Called to clean-up the server.
     50         """
     51         self.socket.close()
     52 
     53     def get_request(self):
     54         """Get the request and client address from the socket.
     55         """
     56         return self.socket.accept()
     57 
     58     def close_request(self, request):
     59         """Called to clean up an individual request."""
     60         request.close()
     61 
     62     def run(self):
     63         while True:
     64             self.conn,self.client_addr=self.get_request()
     65             print('from client ',self.client_addr)
     66             while True:
     67                 try:
     68                     head_struct = self.conn.recv(4)
     69                     if not head_struct:break
     70 
     71                     head_len = struct.unpack('i', head_struct)[0]
     72                     head_json = self.conn.recv(head_len).decode(self.coding)
     73                     head_dic = json.loads(head_json)
     74 
     75                     print(head_dic)
     76                     #head_dic={'cmd':'put','filename':'a.txt','filesize':123123}
     77                     cmd=head_dic['cmd']
     78                     if hasattr(self,cmd):
     79                         func=getattr(self,cmd)
     80                         func(head_dic)
     81                 except Exception:
     82                     break
     83 
     84     def put(self,args):
     85         file_path=os.path.normpath(os.path.join(
     86             self.server_dir,
     87             args['filename']
     88         ))
     89 
     90         filesize=args['filesize']
     91         recv_size=0
     92         print('----->',file_path)
     93         with open(file_path,'wb') as f:
     94             while recv_size < filesize:
     95                 recv_data=self.conn.recv(self.max_packet_size)
     96                 f.write(recv_data)
     97                 recv_size+=len(recv_data)
     98                 print('recvsize:%s filesize:%s' %(recv_size,filesize))
     99 
    100 
    101 tcpserver1=MYTCPServer(('127.0.0.1',8080))
    102 
    103 tcpserver1.run()
    104 
    105 
    106 
    107 
    108 
    109 
    110 #下列代码与本题无关
    111 class MYUDPServer:
    112 
    113     """UDP server class."""
    114     address_family = socket.AF_INET
    115 
    116     socket_type = socket.SOCK_DGRAM
    117 
    118     allow_reuse_address = False
    119 
    120     max_packet_size = 8192
    121 
    122     coding='utf-8'
    123 
    124     def get_request(self):
    125         data, client_addr = self.socket.recvfrom(self.max_packet_size)
    126         return (data, self.socket), client_addr
    127 
    128     def server_activate(self):
    129         # No need to call listen() for UDP.
    130         pass
    131 
    132     def shutdown_request(self, request):
    133         # No need to shutdown anything.
    134         self.close_request(request)
    135 
    136     def close_request(self, request):
    137         # No need to close anything.
    138         pass
    服务端
     1 import socket
     2 import struct
     3 import json
     4 import os
     5 
     6 
     7 class MYTCPClient:
     8     address_family = socket.AF_INET
     9 
    10     socket_type = socket.SOCK_STREAM
    11 
    12     allow_reuse_address = False
    13 
    14     max_packet_size = 8192
    15 
    16     coding='utf-8'
    17 
    18     request_queue_size = 5
    19 
    20     def __init__(self, server_address, connect=True):
    21         self.server_address=server_address
    22         self.socket = socket.socket(self.address_family,
    23                                     self.socket_type)
    24         if connect:
    25             try:
    26                 self.client_connect()
    27             except:
    28                 self.client_close()
    29                 raise
    30 
    31     def client_connect(self):
    32         self.socket.connect(self.server_address)
    33 
    34     def client_close(self):
    35         self.socket.close()
    36 
    37     def run(self):
    38         while True:
    39             inp=input(">>: ").strip()
    40             if not inp:continue
    41             l=inp.split()
    42             cmd=l[0]
    43             if hasattr(self,cmd):
    44                 func=getattr(self,cmd)
    45                 func(l)
    46 
    47 
    48     def put(self,args):
    49         cmd=args[0]
    50         filename=args[1]
    51         if not os.path.isfile(filename):
    52             print('file:%s is not exists' %filename)
    53             return
    54         else:
    55             filesize=os.path.getsize(filename)
    56 
    57         head_dic={'cmd':cmd,'filename':os.path.basename(filename),'filesize':filesize}
    58         print(head_dic)
    59         head_json=json.dumps(head_dic)
    60         head_json_bytes=bytes(head_json,encoding=self.coding)
    61 
    62         head_struct=struct.pack('i',len(head_json_bytes))
    63         self.socket.send(head_struct)
    64         self.socket.send(head_json_bytes)
    65         send_size=0
    66         with open(filename,'rb') as f:
    67             for line in f:
    68                 self.socket.send(line)
    69                 send_size+=len(line)
    70                 print(send_size)
    71             else:
    72                 print('upload successful')
    73 
    74 
    75 
    76 client=MYTCPClient(('127.0.0.1',8080))
    77 
    78 client.run()
    客户端

       

      认证客户端的链接合法性

      如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,那么利用hmac+加盐的方式来实现

     1 #_*_coding:utf-8_*_
     2 __author__ = 'Linhaifeng'
     3 from socket import *
     4 import hmac,os
     5 
     6 secret_key=b'linhaifeng bang bang bang'
     7 def conn_auth(conn):
     8     '''
     9     认证客户端链接
    10     :param conn:
    11     :return:
    12     '''
    13     print('开始验证新链接的合法性')
    14     msg=os.urandom(32)
    15     conn.sendall(msg)
    16     h=hmac.new(secret_key,msg)
    17     digest=h.digest()
    18     respone=conn.recv(len(digest))
    19     return hmac.compare_digest(respone,digest)
    20 
    21 def data_handler(conn,bufsize=1024):
    22     if not conn_auth(conn):
    23         print('该链接不合法,关闭')
    24         conn.close()
    25         return
    26     print('链接合法,开始通信')
    27     while True:
    28         data=conn.recv(bufsize)
    29         if not data:break
    30         conn.sendall(data.upper())
    31 
    32 def server_handler(ip_port,bufsize,backlog=5):
    33     '''
    34     只处理链接
    35     :param ip_port:
    36     :return:
    37     '''
    38     tcp_socket_server=socket(AF_INET,SOCK_STREAM)
    39     tcp_socket_server.bind(ip_port)
    40     tcp_socket_server.listen(backlog)
    41     while True:
    42         conn,addr=tcp_socket_server.accept()
    43         print('新连接[%s:%s]' %(addr[0],addr[1]))
    44         data_handler(conn,bufsize)
    45 
    46 if __name__ == '__main__':
    47     ip_port=('127.0.0.1',9999)
    48     bufsize=1024
    49     server_handler(ip_port,bufsize)
    服务端
     1 #_*_coding:utf-8_*_
     2 __author__ = 'Linhaifeng'
     3 from socket import *
     4 import hmac,os
     5 
     6 secret_key=b'linhaifeng bang bang bang'
     7 def conn_auth(conn):
     8     '''
     9     验证客户端到服务器的链接
    10     :param conn:
    11     :return:
    12     '''
    13     msg=conn.recv(32)
    14     h=hmac.new(secret_key,msg)
    15     digest=h.digest()
    16     conn.sendall(digest)
    17 
    18 def client_handler(ip_port,bufsize=1024):
    19     tcp_socket_client=socket(AF_INET,SOCK_STREAM)
    20     tcp_socket_client.connect(ip_port)
    21 
    22     conn_auth(tcp_socket_client)
    23 
    24     while True:
    25         data=input('>>: ').strip()
    26         if not data:continue
    27         if data == 'quit':break
    28 
    29         tcp_socket_client.sendall(data.encode('utf-8'))
    30         respone=tcp_socket_client.recv(bufsize)
    31         print(respone.decode('utf-8'))
    32     tcp_socket_client.close()
    33 
    34 if __name__ == '__main__':
    35     ip_port=('127.0.0.1',9999)
    36     bufsize=1024
    37     client_handler(ip_port,bufsize)
    客户端(合法)
     1 #_*_coding:utf-8_*_
     2 __author__ = 'Linhaifeng'
     3 from socket import *
     4 
     5 def client_handler(ip_port,bufsize=1024):
     6     tcp_socket_client=socket(AF_INET,SOCK_STREAM)
     7     tcp_socket_client.connect(ip_port)
     8 
     9     while True:
    10         data=input('>>: ').strip()
    11         if not data:continue
    12         if data == 'quit':break
    13 
    14         tcp_socket_client.sendall(data.encode('utf-8'))
    15         respone=tcp_socket_client.recv(bufsize)
    16         print(respone.decode('utf-8'))
    17     tcp_socket_client.close()
    18 
    19 if __name__ == '__main__':
    20     ip_port=('127.0.0.1',9999)
    21     bufsize=1024
    22     client_handler(ip_port,bufsize)
    客户端(非法:不知道加密方式)
     1 #_*_coding:utf-8_*_
     2 __author__ = 'Linhaifeng'
     3 from socket import *
     4 import hmac,os
     5 
     6 secret_key=b'linhaifeng bang bang bang1111'
     7 def conn_auth(conn):
     8     '''
     9     验证客户端到服务器的链接
    10     :param conn:
    11     :return:
    12     '''
    13     msg=conn.recv(32)
    14     h=hmac.new(secret_key,msg)
    15     digest=h.digest()
    16     conn.sendall(digest)
    17 
    18 def client_handler(ip_port,bufsize=1024):
    19     tcp_socket_client=socket(AF_INET,SOCK_STREAM)
    20     tcp_socket_client.connect(ip_port)
    21 
    22     conn_auth(tcp_socket_client)
    23 
    24     while True:
    25         data=input('>>: ').strip()
    26         if not data:continue
    27         if data == 'quit':break
    28 
    29         tcp_socket_client.sendall(data.encode('utf-8'))
    30         respone=tcp_socket_client.recv(bufsize)
    31         print(respone.decode('utf-8'))
    32     tcp_socket_client.close()
    33 
    34 if __name__ == '__main__':
    35     ip_port=('127.0.0.1',9999)
    36     bufsize=1024
    37     client_handler(ip_port,bufsize)
    客户端(非法:不知道secret_key)

       

      socketserver实现并发

      基于tcp的套接字,关键就是两个循环,一个链接循环,一个通信循环

      socketserver模块中分两大类:server类(解决链接问题)和request类(解决通信问题)

      server类:

            

      request类:

            

          

      继承关系:

          

          

      

          

       

            

      以下述代码为例,分析socketserver源码:

        ftpserver=socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer)
        ftpserver.serve_forever()

      查找属性的顺序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServer

    1. 实例化得到ftpserver,先找类ThreadingTCPServer的__init__,在TCPServer中找到,进而执行server_bind,server_active
    2. 找ftpserver下的serve_forever,在BaseServer中找到,进而执行self._handle_request_noblock(),该方法同样是在BaseServer中
    3. 执行self._handle_request_noblock()进而执行request, client_address = self.get_request()(就是TCPServer中的self.socket.accept()),然后执行self.process_request(request, client_address)
    4. 在ThreadingMixIn中找到process_request,开启多线程应对并发,进而执行process_request_thread,执行self.finish_request(request, client_address)
    5. 上述四部分完成了链接循环,本部分开始进入处理通讯部分,在BaseServer中找到finish_request,触发我们自己定义的类的实例化,去找__init__方法,而我们自己定义的类没有该方法,则去它的父类也就是BaseRequestHandler中找....

      源码分析总结:

      基于tcp的socketserver我们自己定义的类中的

    1. self.server即套接字对象
    2. self.request即一个链接
    3. self.client_address即客户端地址

      基于udp的socketserver我们自己定义的类中的

    1. self.request是一个元组(第一个元素是客户端发来的数据,第二部分是服务端的udp套接字对象),如(b'adsf', <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>)
    2. self.client_address即客户端地址
     1 import socketserver
     2 import struct
     3 import json
     4 import os
     5 class FtpServer(socketserver.BaseRequestHandler):
     6     coding='utf-8'
     7     server_dir='file_upload'
     8     max_packet_size=1024
     9     BASE_DIR=os.path.dirname(os.path.abspath(__file__))
    10     def handle(self):
    11         print(self.request)
    12         while True:
    13             data=self.request.recv(4)
    14             data_len=struct.unpack('i',data)[0]
    15             head_json=self.request.recv(data_len).decode(self.coding)
    16             head_dic=json.loads(head_json)
    17             # print(head_dic)
    18             cmd=head_dic['cmd']
    19             if hasattr(self,cmd):
    20                 func=getattr(self,cmd)
    21                 func(head_dic)
    22     def put(self,args):
    23         file_path = os.path.normpath(os.path.join(
    24             self.BASE_DIR,
    25             self.server_dir,
    26             args['filename']
    27         ))
    28 
    29         filesize = args['filesize']
    30         recv_size = 0
    31         print('----->', file_path)
    32         with open(file_path, 'wb') as f:
    33             while recv_size < filesize:
    34                 recv_data = self.request.recv(self.max_packet_size)
    35                 f.write(recv_data)
    36                 recv_size += len(recv_data)
    37                 print('recvsize:%s filesize:%s' % (recv_size, filesize))
    38 
    39 
    40 ftpserver=socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer)
    41 ftpserver.serve_forever()
    FtpServer
     1 import socket
     2 import struct
     3 import json
     4 import os
     5 
     6 
     7 
     8 class MYTCPClient:
     9     address_family = socket.AF_INET
    10 
    11     socket_type = socket.SOCK_STREAM
    12 
    13     allow_reuse_address = False
    14 
    15     max_packet_size = 8192
    16 
    17     coding='utf-8'
    18 
    19     request_queue_size = 5
    20 
    21     def __init__(self, server_address, connect=True):
    22         self.server_address=server_address
    23         self.socket = socket.socket(self.address_family,
    24                                     self.socket_type)
    25         if connect:
    26             try:
    27                 self.client_connect()
    28             except:
    29                 self.client_close()
    30                 raise
    31 
    32     def client_connect(self):
    33         self.socket.connect(self.server_address)
    34 
    35     def client_close(self):
    36         self.socket.close()
    37 
    38     def run(self):
    39         while True:
    40             inp=input(">>: ").strip()
    41             if not inp:continue
    42             l=inp.split()
    43             cmd=l[0]
    44             if hasattr(self,cmd):
    45                 func=getattr(self,cmd)
    46                 func(l)
    47 
    48 
    49     def put(self,args):
    50         cmd=args[0]
    51         filename=args[1]
    52         if not os.path.isfile(filename):
    53             print('file:%s is not exists' %filename)
    54             return
    55         else:
    56             filesize=os.path.getsize(filename)
    57 
    58         head_dic={'cmd':cmd,'filename':os.path.basename(filename),'filesize':filesize}
    59         print(head_dic)
    60         head_json=json.dumps(head_dic)
    61         head_json_bytes=bytes(head_json,encoding=self.coding)
    62 
    63         head_struct=struct.pack('i',len(head_json_bytes))
    64         self.socket.send(head_struct)
    65         self.socket.send(head_json_bytes)
    66         send_size=0
    67         with open(filename,'rb') as f:
    68             for line in f:
    69                 self.socket.send(line)
    70                 send_size+=len(line)
    71                 print(send_size)
    72             else:
    73                 print('upload successful')
    74 
    75 
    76 
    77 
    78 client=MYTCPClient(('127.0.0.1',8080))
    79 
    80 client.run()
    FtpClient

       作业:

        

    并发的FTP:

      Server端:

     1 import socketserver
     2 import struct
     3 import json
     4 import subprocess
     5 import os
     6 
     7 class MYTCPServer(socketserver.BaseRequestHandler):
     8 
     9     max_packet_size = 8192
    10 
    11     coding='utf-8'
    12     BASE_DIR=os.path.dirname(os.path.abspath(__file__))
    13 
    14     server_dir='file_upload'
    15 
    16     def handle(self):
    17         while True:
    18             try:
    19                 head_struct = self.request.recv(4)
    20                 if not head_struct:break
    21 
    22                 head_len = struct.unpack('i', head_struct)[0]
    23                 head_json = self.request.recv(head_len).decode(self.coding)
    24                 head_dic = json.loads(head_json)
    25 
    26                 print(head_dic)
    27                 #head_dic={'cmd':'put','filename':'a.txt','filesize':123123}
    28                 cmd=head_dic['cmd']
    29                 if hasattr(self,cmd):
    30                     func=getattr(self,cmd)
    31                     func(head_dic)
    32             except Exception:
    33                 break
    34 
    35     def put(self,args):
    36         file_path=os.path.normpath(os.path.join(
    37             self.BASE_DIR,
    38             self.server_dir,
    39             args['filename']
    40         ))
    41 
    42         filesize=args['filesize']
    43         recv_size=0
    44         print('----->',file_path)
    45         with open(file_path,'wb') as f:
    46             while recv_size < filesize:
    47                 recv_data=self.request.recv(self.max_packet_size)
    48                 f.write(recv_data)
    49                 recv_size+=len(recv_data)
    50                 print('recvsize:%s filesize:%s' %(recv_size,filesize))
    51 
    52 
    53 
    54 
    55 if __name__ == '__main__':
    56     obj=socketserver.ThreadingTCPServer(('127.0.0.1',8080),MYTCPServer)
    57     obj.serve_forever()
    View Code

      Client端1:

     1 import socket
     2 import struct
     3 import json
     4 import os
     5 
     6 
     7 
     8 class MYTCPClient:
     9     address_family = socket.AF_INET
    10 
    11     socket_type = socket.SOCK_STREAM
    12 
    13     allow_reuse_address = False
    14 
    15     max_packet_size = 8192
    16 
    17     coding='utf-8'
    18 
    19     request_queue_size = 5
    20 
    21     def __init__(self, server_address, connect=True):
    22         self.server_address=server_address
    23         self.socket = socket.socket(self.address_family,
    24                                     self.socket_type)
    25         if connect:
    26             try:
    27                 self.client_connect()
    28             except:
    29                 self.client_close()
    30                 raise
    31 
    32     def client_connect(self):
    33         self.socket.connect(self.server_address)
    34 
    35     def client_close(self):
    36         self.socket.close()
    37 
    38     def run(self):
    39         while True:
    40             inp=input(">>: ").strip()
    41             if not inp:continue
    42             l=inp.split()
    43             cmd=l[0]
    44             if hasattr(self,cmd):
    45                 func=getattr(self,cmd)
    46                 func(l)
    47 
    48 
    49     def put(self,args):
    50         cmd=args[0]
    51         filename=args[1]
    52         if not os.path.isfile(filename):
    53             print('file:%s is not exists' %filename)
    54             return
    55         else:
    56             filesize=os.path.getsize(filename)
    57 
    58         head_dic={'cmd':cmd,'filename':os.path.basename(filename),'filesize':filesize}
    59         print(head_dic)
    60         head_json=json.dumps(head_dic)
    61         head_json_bytes=bytes(head_json,encoding=self.coding)
    62 
    63         head_struct=struct.pack('i',len(head_json_bytes))
    64         self.socket.send(head_struct)
    65         self.socket.send(head_json_bytes)
    66         send_size=0
    67         with open(filename,'rb') as f:
    68             for line in f:
    69                 self.socket.send(line)
    70                 send_size+=len(line)
    71                 print(send_size)
    72             else:
    73                 print('upload successful')
    74 
    75 
    76 
    77 
    78 client=MYTCPClient(('127.0.0.1',8080))
    79 
    80 client.run()
    View Code

      Client端2:

     1 import socket
     2 import struct
     3 import json
     4 import os
     5 
     6 
     7 
     8 class MYTCPClient:
     9     address_family = socket.AF_INET
    10 
    11     socket_type = socket.SOCK_STREAM
    12 
    13     allow_reuse_address = False
    14 
    15     max_packet_size = 8192
    16 
    17     coding='utf-8'
    18 
    19     request_queue_size = 5
    20 
    21     def __init__(self, server_address, connect=True):
    22         self.server_address=server_address
    23         self.socket = socket.socket(self.address_family,
    24                                     self.socket_type)
    25         if connect:
    26             try:
    27                 self.client_connect()
    28             except:
    29                 self.client_close()
    30                 raise
    31 
    32     def client_connect(self):
    33         self.socket.connect(self.server_address)
    34 
    35     def client_close(self):
    36         self.socket.close()
    37 
    38     def run(self):
    39         while True:
    40             inp=input(">>: ").strip()
    41             if not inp:continue
    42             l=inp.split()
    43             cmd=l[0]
    44             if hasattr(self,cmd):
    45                 func=getattr(self,cmd)
    46                 func(l)
    47 
    48 
    49     def put(self,args):
    50         cmd=args[0]
    51         filename=args[1]
    52         if not os.path.isfile(filename):
    53             print('file:%s is not exists' %filename)
    54             return
    55         else:
    56             filesize=os.path.getsize(filename)
    57 
    58         head_dic={'cmd':cmd,'filename':os.path.basename(filename),'filesize':filesize}
    59         print(head_dic)
    60         head_json=json.dumps(head_dic)
    61         head_json_bytes=bytes(head_json,encoding=self.coding)
    62 
    63         head_struct=struct.pack('i',len(head_json_bytes))
    64         self.socket.send(head_struct)
    65         self.socket.send(head_json_bytes)
    66         send_size=0
    67         with open(filename,'rb') as f:
    68             for line in f:
    69                 self.socket.send(line)
    70                 send_size+=len(line)
    71                 print(send_size)
    72             else:
    73                 print('upload successful')
    74 
    75 
    76 
    77 
    78 client=MYTCPClient(('127.0.0.1',8080))
    79 
    80 client.run()
    View Code

      加一个file_upload文件包。

      

  • 相关阅读:
    java设计模式----迭代器模式和组合模式
    Redis实现消息的发布/订阅
    java设计模式----模板方法模式
    java设计模式----适配器模式
    Filter注入对象
    java设计模式----命令模式
    css3中animation的应用
    bootstrap的学习注意点
    关于animate的一些属性
    ie的兼容方法,条件注释的方法
  • 原文地址:https://www.cnblogs.com/george92/p/9318185.html
Copyright © 2011-2022 走看看