>  기사  >  백엔드 개발  >  소켓을 사용하여 FTP를 구현하는 방법에 대한 자습서

소켓을 사용하여 FTP를 구현하는 방법에 대한 자습서

巴扎黑
巴扎黑원래의
2017-07-18 13:48:272663검색
 
    1、用户加密认证
    2、允许同时多用户登录
    3、每个用户有自己的家目录 ,且只能访问自己的家目录
    4、对用户进行磁盘配额,每个用户的可用空间不同
    5、允许用户在ftp server上随意切换目录
    6、允许用户查看当前目录下文件
    7、允许上传和下载文件,保证文件一致性
    8、文件传输过程中显示进度条
    附加功能:支持文件的断点续传

python 3.5


  用socketserver实现FTP


  
    ConfigParser 是Python自带的模块, 用来读写配置文件,将用户信息以下边的格式存入account.py文件,读出后进行判断
[DEFAULT]

[alex]
Password = 123456Quotation = 100[jack]
Password = 123456Quotation = 100

 

    2、允许同时多用户登录
      从scokerserver 继承 socketserver.ThreadingTCPServer即可实现
    3、每个用户有自己的家目录 ,且只能访问自己的家目录
      将所有路径封装在home目录下
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

USER_HOME = '%s\home' % BASE_DIR
LOG_DIR = '%s\log' % BASE_DIR
LOG_LEVEL = 'DEBUG'

 

    4、允许用户在ftp server上随意切换目录
      用os模块改变工作目录
os.chdir(func_val)

 

    5、允许用户查看当前目录下文件
      用os模块的os.listdir,下为server端代码
    def _ls(self,*args,**kwargs):'''显示当前目录下的所有文件'''if os.getcwd() == '%s\\bin'% settings.BASE_DIR:
            user_home_dir = "%s\%s" % (settings.USER_HOME, self.user["Username"])
            self.request.send(json.dumps(os.listdir(user_home_dir)).encode())else:self.request.send(json.dumps(os.listdir()).encode())

 

    6、允许上传和下载文件,保证文件一致性
      判断上传和下载的文件在传输前后的大小,用以判断文件是否保持一致
  1 #server端  2 #  3     def _put(self,*args,**kwargs):  4         '''上传文件命令'''  5         data = args[0]  6   7         response = self.get_response()  8         if response["status_code"] == 257:  # ready to receive  9             self.request.send(b'1')  # send confirmation to server 10             user_home_dir = "%s\%s" % (settings.USER_HOME, self.user["Username"]) 11             base_filename = "%s\%s" % (user_home_dir, data.get('filename')) 12             received_size = 0 13             file_obj = open(base_filename, 'wb') 14             if data.get('md5'): 15                 md5_obj = hashlib.md5() 16                 while received_size < response[&#39;file_size&#39;]: 17                     line = self.request.recv(4096) 18                     received_size += len(line) 19                     file_obj.write(line) 20                     md5_obj.update(line) 21                 else: 22                     file_obj.close() 23                     md5_val = md5_obj.hexdigest() 24                     self.send_response(258, {&#39;md5&#39;: md5_val}) 25                     print("-----file rece done-----") 26  27             else: 28                 while received_size < response[&#39;file_size&#39;]: 29                     data = self.request.recv(4096) 30                     received_size += len(data) 31                     file_obj.write(data) 32                 else: 33                     print("-----file rece done-----") 34                     file_obj.close() 35         else: 36             print(STATUS_CODE[response["status_code"]]) 37  38  39     def _get(self,*args,**kwargs): 40         &#39;&#39;&#39;下载文件命令&#39;&#39;&#39; 41         data = args[0] 42         if data.get(&#39;filename&#39;) is None: 43             self.send_response(255) 44         user_home_dir = "%s\%s" %(settings.USER_HOME,self.user["Username"]) 45         file_abs_path = "%s\%s" %(user_home_dir,data.get(&#39;filename&#39;)) 46         print("file abs path",file_abs_path) 47  48         if os.path.isfile(file_abs_path): 49             file_obj = open(file_abs_path,&#39;rb&#39;) 50             file_size = os.path.getsize(file_abs_path) 51             self.send_response(257,data = {&#39;file_size&#39;:file_size}) 52             self.request.recv(1)    #等待客户端确认,防粘包 53  54             if data.get(&#39;md5&#39;): 55                 md5_obj = hashlib.md5() 56                 for line in file_obj: 57                     self.request.send(line) 58                     md5_obj.update(line) 59                 else: 60                     file_obj.close() 61                     md5_val = md5_obj.hexdigest() 62                     self.send_response(258,{&#39;md5&#39;:md5_val}) 63                     print("send file done...") 64             else: 65                 for line in file_obj: 66                     self.request.send(line) 67                 else: 68                     file_obj.close() 69                     print("send file done...") 70         else: 71             self.send_response(256) 72  73  74  75  76 # client端 77 # 78     def _get(self,cmd_list): 79         &#39;&#39;&#39;下载文件&#39;&#39;&#39; 80         print("get--",cmd_list) 81         if len(cmd_list) == 1: 82             print("no filename follows...") 83             return 84         data_header = { 85             &#39;action&#39;:&#39;get&#39;, 86             &#39;filename&#39;:cmd_list[1] 87         } 88         if self.__md5_required(cmd_list): 89             data_header[&#39;md5&#39;] = True 90  91         self.sock.send(json.dumps(data_header).encode()) 92         response = self.get_response() 93         print(response) 94         try: 95             if response["status_code"] == 257:#ready to receive 96                 self.sock.send(b&#39;1&#39;) #send confirmation to server 97                 base_filename = cmd_list[1].split(&#39;/&#39;)[-1] 98                 received_size = 0 99                 file_obj = open(base_filename,&#39;wb&#39;)100                 if self.__md5_required(cmd_list):101                     md5_obj = hashlib.md5()102                     progress = self.show_progress(response[&#39;file_size&#39;]) #generator103                     progress.__next__()104                     while received_size < response[&#39;file_size&#39;]:105                         data = self.sock.recv(4096)106                         received_size += len(data)107                         try:108                             progress.send(len(data))109                         except StopIteration as e:110                             print("100%")111                         file_obj.write(data)112                         md5_obj.update(data)113                     else:114                         print("-----file rece done-----")115                         file_obj.close()116                         md5_val = md5_obj.hexdigest()117                         md5_from_server = self.get_response()118                         if md5_from_server[&#39;status_code&#39;] == 258:119                             if md5_from_server[&#39;md5&#39;] == md5_val:120                                 print("%s 文件一致性校验成功!"% base_filename)121                         print(md5_val,md5_from_server)122 123                 else:124                     progress = self.show_progress(response[&#39;file_size&#39;])  # generator125                     progress.__next__()126                     while received_size < response[&#39;file_size&#39;]:127                         data = self.sock.recv(4096)128                         received_size += len(data)129                         file_obj.write(data)130                         try:131                             progress.send(len(data))132                         except StopIteration as e:133                             print("100%")134                     else:135                         print("-----file rece done-----")136                         file_obj.close()137             else:138                 print(STATUS_CODE[response["status_code"]])139         except Exception as e:140             base_file_size = os.path.getsize(base_filename)141             with open(&#39;data\\breakpoint&#39;, &#39;wb&#39;) as br_po:142                 data_header[&#39;action&#39;] = &#39;breakpoint&#39;143                 data_header[&#39;breakpoint&#39;] = base_file_size144                 br_po.write(json.dumps(data_header).encode())145 146 147     def _put(self,cmd_list):148         &#39;&#39;&#39;上传文件&#39;&#39;&#39;149         print("put--", cmd_list)150         if len(cmd_list) == 1:151             print("no filename follows...")152             return153         data_header = {154             &#39;action&#39;: &#39;put&#39;,155             &#39;filename&#39;: cmd_list[1]156         }157         if self.__md5_required(cmd_list):158             data_header[&#39;md5&#39;] = True159 160         self.sock.send(json.dumps(data_header).encode())161         if os.path.isfile(cmd_list[1]):162             file_obj = open(cmd_list[1], &#39;rb&#39;)163             file_size = os.path.getsize(cmd_list[1])164             self.send_response(257, data={&#39;file_size&#39;: file_size})165             self.sock.recv(1)  # 等待服务器端确认166             if self.__md5_required(cmd_list):167                 md5_obj = hashlib.md5()168                 progress = self.show_progress(file_size)  # generator169                 progress.__next__()170                 for line in file_obj:171                     self.sock.send(line)172                     try:173                         progress.send(len(line))174                     except StopIteration as e:175                         print("100%")176                     md5_obj.update(line)177                 else:178                     file_obj.close()179                     md5_val = md5_obj.hexdigest()180                     md5_from_server = self.get_response()181                     if md5_from_server[&#39;md5&#39;] == md5_val:182                             print("%s 文件一致性校验成功!"% cmd_list[1])183                     self.send_response(258, {&#39;md5&#39;: md5_val})184                     print("send file done...")185             else:186                 progress = self.show_progress(file_size)  # generator187                 progress.__next__()188                 for line in file_obj:189                     self.sock.send(line)190                     try:191                         progress.send(len(line))192                     except StopIteration as e:193                         print("100%")194                 else:195                     file_obj.close()196                     print("send file done...")197         else:198             print(256)
get and put

    7、文件传输过程中显示进度条
      根据已传文件大小和总文件大小比对判断,输出符号
 1     def show_progress(self,total): 2         &#39;&#39;&#39;显示进度条 3            total: 文件大小&#39;&#39;&#39; 4         received_size = 0 5         current_percent = 0 6         while received_size < total: 7             if int((received_size / total) * 100) > current_percent: 8                 print(">",end='',flush=True) 9                 current_percent = int((received_size / total) * 100)10             new_size = yield11             received_size += new_size
进度条

 

    附加功能:支持文件的断点续传
      将上次断点信息记录下来,也就是记录已传文件大小,再次启用时,将目标文件光标移到上次断点处,然后进行续传
 1     def _breakpoint(self,*args,**kwargs): 2         '''断点续传''' 3         data = args[0] 4         if data.get('filename') is None: 5             self.send_response(255) 6         user_home_dir = "%s\%s" % (settings.USER_HOME, self.user["Username"]) 7         file_abs_path = "%s\%s" % (user_home_dir, data.get('filename')) 8         print("file abs path", file_abs_path) 9         print(data.get('breakpoint'))10 11         if os.path.isfile(file_abs_path):12             file_obj = open(file_abs_path, 'rb')13             file_obj.seek(data.get('breakpoint'))14             file_size = os.path.getsize(file_abs_path)15             self.send_response(257, data={'file_size': file_size})16             self.request.recv(1)  # 等待客户端确认17 18             if data.get('md5'):19                 md5_obj = hashlib.md5()20                 for line in file_obj:21                     self.request.send(line)22                     md5_obj.update(line)23                 else:24                     file_obj.close()25                     md5_val = md5_obj.hexdigest()26                     self.send_response(258, {'md5': md5_val})27                     print("send file done...")28             else:29                 for line in file_obj:30                     self.request.send(line)31                 else:32                     file_obj.close()33                     print("send file done...")34         else:35             self.send_response(256)36         pass
breakpoint

   主要知识点:

    类的继承
    os模块的应用
    json模块的应用
    类方法的运用
    md5加密方法
    scoket链接
    scoketserver链接
    反射
    异常处理


小结:
          这个程序主要用socketserver实现了一台服务器链接多个客户端,并且进行信息交互,并且实现了几个简单的功能,如:get 文件下载、put 上传文件、cd 切换目录、ls 查看文件、breakpoint断点续传。

主要代码:
  1 #server端  2 #  3   4   5 import os,sys  6 import hashlib  7 import socket  8 import socketserver  9 import json 10 import configparser 11 from conf import settings 12  13  14 STATUS_CODE = { 15     250 : "Invalid cmd format,e.g:{'action':'get','filename':'test.py','size':344", 16     251 : "Invalid cmd", 17     252 : "Invalid auth data", 18     253 : "Wrong username or password..", 19     254 : "Passed authentication", 20     255 : "Filename doesn't provided", 21     256 : "File doesn't exist on server", 22     257 : "ready to send file", 23     258 : "md5 verification", 24     259 : "Directory has been switched" 25 } 26  27  28  29  30  31 class FTPHandler(socketserver.BaseRequestHandler): 32     '''定义request handler类,从BaseRequestHandler类继承''' 33     def handle(self): 34         ''' 35         获取服务器端的信息 36         如果传来cd命令,改变工作目录 37         ''' 38  39         while True: 40             self.data = self.request.recv(1024).strip() 41             if not self.data: 42                 print('Client closed..') 43                 break 44             data = json.loads(self.data.decode()) 45             if data.get('action') is not None: 46                 if hasattr(self,'_%s'%data.get('action')): 47                     func =getattr(self,'_%s'%data.get('action')) 48                     func_val = func(data) 49                     if data.get('action') == 'cd':     #cd 命令,改变工作目录 50                         os.chdir(func_val) 51                     else:pass 52                 else: 53                     print('Invalid cmd') 54                     self.send_response(251) 55             else: 56                 print('Invalid cmd format') 57                 self.send_response(250) 58  59  60     def send_response(self,status_code,data=None): 61         '''向客户端返回数据''' 62         response = {'status_code': status_code, 'status_msg':STATUS_CODE[status_code]} 63         if data: 64             response.update(data) 65         self.request.send(json.dumps(response).encode()) 66  67  68     def _auth(self,*args,**kwargs): 69         '''判断用户是否输入完整的用户名和密码 70            验证用户名和密码是否合法''' 71         data = args[0] 72         if data.get('username') is None or data.get('password') is None: 73             self.send_response(252) 74  75         user = self.authenticate(data.get('username'),data.get('password')) 76         if user is None: 77             self.send_response(253) 78         else: 79             print('passed authentication',user) 80             self.user = user 81             self.send_response(254) 82  83  84     def authenticate(self,username,password):       # 85         '''验证用户合法性,合法返回用户数据''' 86         config = configparser.ConfigParser() 87         config.read(settings.ACCOUNT_FILE) 88         if username in config.sections(): 89             _password = config[username]['Password'] 90             if _password == password: 91                 print('pass auth..',username) 92                 config[username]["Username"] = username 93                 return config[username] 94  95  96     def get_response(self): 97         '''接收客户端回复结果''' 98         data = self.request.recv(1024) 99         data = json.loads(data.decode())100         return data101 102 103     def show_progress(self,total):104         '''显示进度条105            total: 文件大小'''106         received_size = 0107         current_percent = 0108         while received_size < total:109             if int((received_size / total) * 100) > current_percent:110                 print(">",end='',flush=True)111                 current_percent = int((received_size / total) * 100)112             new_size = yield113             received_size += new_size114 115 116     def _put(self,*args,**kwargs):117         '''上传文件命令'''118         data = args[0]119 120         response = self.get_response()121         if response["status_code"] == 257:  # ready to receive122             self.request.send(b'1')  # send confirmation to server123             user_home_dir = "%s\%s" % (settings.USER_HOME, self.user["Username"])124             base_filename = "%s\%s" % (user_home_dir, data.get('filename'))125             received_size = 0126             file_obj = open(base_filename, 'wb')127             if data.get('md5'):128                 md5_obj = hashlib.md5()129                 while received_size < response[&#39;file_size&#39;]:130                     line = self.request.recv(4096)131                     received_size += len(line)132                     file_obj.write(line)133                     md5_obj.update(line)134                 else:135                     file_obj.close()136                     md5_val = md5_obj.hexdigest()137                     self.send_response(258, {&#39;md5&#39;: md5_val})138                     print("-----file rece done-----")139 140             else:141                 while received_size < response[&#39;file_size&#39;]:142                     data = self.request.recv(4096)143                     received_size += len(data)144                     file_obj.write(data)145                 else:146                     print("-----file rece done-----")147                     file_obj.close()148         else:149             print(STATUS_CODE[response["status_code"]])150 151 152     def _get(self,*args,**kwargs):153         &#39;&#39;&#39;下载文件命令&#39;&#39;&#39;154         data = args[0]155         if data.get(&#39;filename&#39;) is None:156             self.send_response(255)157         user_home_dir = "%s\%s" %(settings.USER_HOME,self.user["Username"])158         file_abs_path = "%s\%s" %(user_home_dir,data.get(&#39;filename&#39;))159         print("file abs path",file_abs_path)160 161         if os.path.isfile(file_abs_path):162             file_obj = open(file_abs_path,&#39;rb&#39;)163             file_size = os.path.getsize(file_abs_path)164             self.send_response(257,data = {&#39;file_size&#39;:file_size})165             self.request.recv(1)    #等待客户端确认,防粘包166 167             if data.get(&#39;md5&#39;):168                 md5_obj = hashlib.md5()169                 for line in file_obj:170                     self.request.send(line)171                     md5_obj.update(line)172                 else:173                     file_obj.close()174                     md5_val = md5_obj.hexdigest()175                     self.send_response(258,{&#39;md5&#39;:md5_val})176                     print("send file done...")177             else:178                 for line in file_obj:179                     self.request.send(line)180                 else:181                     file_obj.close()182                     print("send file done...")183         else:184             self.send_response(256)185 186 187 188     def _ls(self,*args,**kwargs):189         &#39;&#39;&#39;显示当前目录下的所有文件&#39;&#39;&#39;190         if os.getcwd() == &#39;%s\\bin&#39;% settings.BASE_DIR:191             user_home_dir = "%s\%s" % (settings.USER_HOME, self.user["Username"])192             self.request.send(json.dumps(os.listdir(user_home_dir)).encode())193         else:self.request.send(json.dumps(os.listdir()).encode())194 195 196 197     def _cd(self,*args,**kwargs):198         &#39;&#39;&#39;改变工作目录&#39;&#39;&#39;199         data = args[0]200         user_home_dir = "%s\%s" % (settings.USER_HOME, self.user["Username"])201         file_abs_path = "%s\%s" %(user_home_dir,data.get(&#39;path&#39;))202         try:203             os.listdir(file_abs_path)204         except FileNotFoundError as e:205             self.request.send(json.dumps(e).encode())206             return207         self.request.send(json.dumps(259).encode())208         os.chdir(file_abs_path)209         return file_abs_path210 211 212     def _breakpoint(self,*args,**kwargs):213         &#39;&#39;&#39;断点续传&#39;&#39;&#39;214         data = args[0]215         if data.get(&#39;filename&#39;) is None:216             self.send_response(255)217         user_home_dir = "%s\%s" % (settings.USER_HOME, self.user["Username"])218         file_abs_path = "%s\%s" % (user_home_dir, data.get(&#39;filename&#39;))219         print("file abs path", file_abs_path)220         print(data.get(&#39;breakpoint&#39;))221 222         if os.path.isfile(file_abs_path):223             file_obj = open(file_abs_path, &#39;rb&#39;)224             file_obj.seek(data.get(&#39;breakpoint&#39;))225             file_size = os.path.getsize(file_abs_path)226             self.send_response(257, data={&#39;file_size&#39;: file_size})227             self.request.recv(1)  # 等待客户端确认228 229             if data.get(&#39;md5&#39;):230                 md5_obj = hashlib.md5()231                 for line in file_obj:232                     self.request.send(line)233                     md5_obj.update(line)234                 else:235                     file_obj.close()236                     md5_val = md5_obj.hexdigest()237                     self.send_response(258, {&#39;md5&#39;: md5_val})238                     print("send file done...")239             else:240                 for line in file_obj:241                     self.request.send(line)242                 else:243                     file_obj.close()244                     print("send file done...")245         else:246             self.send_response(256)247         pass
server端
  1 #client端  2 #  3   4 import socket  5 import hashlib  6 import os,json  7 import optparse  8 import socketserver  9  10  11 STATUS_CODE = { 12     250 : "Invalid cmd format,e.g:{&#39;action&#39;:&#39;get&#39;,&#39;filename&#39;:&#39;test.py&#39;,&#39;size&#39;:344", 13     251 : "Invalid cmd", 14     252 : "Invalid auth data", 15     253 : "Wrong username or password..", 16     254 : "Passed authentication", 17     255 : "Filename doesn&#39;t provided", 18     256 : "File doesn&#39;t exist on server", 19     257 : "ready to send file", 20     258 : "md5 verification", 21     259 : "Directory has been switched" 22 } 23  24  25  26  27 class FTPClient(object): 28     &#39;&#39;&#39;客户端&#39;&#39;&#39; 29     def __init__(self): 30         &#39;&#39;&#39;用户信息输入格式化 31             变量定义&#39;&#39;&#39; 32         parser = optparse.OptionParser() 33         parser.add_option(&#39;-s&#39;, &#39;--server&#39;, dest=&#39;server&#39;, help =&#39;ftp server ip_addr&#39;) 34         parser.add_option(&#39;-p&#39;,&#39;--port&#39;, type=&#39;int&#39;, dest=&#39;port&#39;, help=&#39;ftp server port&#39;) 35         parser.add_option(&#39;-U&#39;, &#39;--username&#39;, dest=&#39;username&#39;, help=&#39;username&#39;) 36         parser.add_option(&#39;-P&#39;, &#39;--Password&#39;, dest=&#39;password&#39;, help=&#39;password&#39;) 37         self.options, self.args = parser.parse_args() 38         self.verify_args(self.options,self.args) 39         self.make_connection() 40  41  42     def make_connection(self): 43         &#39;&#39;&#39;连接服务器&#39;&#39;&#39; 44         self.sock = socket.socket() 45         self.sock.connect((self.options.server,self.options.port)) 46  47  48  49     def verify_args(self,options,args): 50         &#39;&#39;&#39;校验参数合法性&#39;&#39;&#39; 51         if options.username and options.password: 52             pass 53         elif options.username is None and options.password is None: 54             pass 55         else: 56             if options.username is None or options.password is None: 57                 print(&#39;Error:username and password must be provided together..&#39;) 58         if options.server and options.port: 59             if options.port > 0 and options.port < 65535: 60                 return True 61             else: 62                 exit(&#39;Err:host port must in 0-65535&#39;) 63  64  65     def authenticate(self): 66         &#39;&#39;&#39;用户验证&#39;&#39;&#39; 67         if self.options.username: 68             return self.get_auth_result(self.options.username, self.options.password) 69         else: 70             retry_count = 0 71             while retry_count < 3: 72                 username = input("username:").strip() 73                 password = input("password:").strip() 74                 return self.get_auth_result(username,password) 75  76  77  78  79     def get_auth_result(self,user,password): 80         &#39;&#39;&#39;用户认证&#39;&#39;&#39; 81         data = {&#39;action&#39;:&#39;auth&#39;, 82                 &#39;username&#39;:user, 83                 &#39;password&#39;:password} 84  85         self.sock.send(json.dumps(data).encode()) 86         response = self.get_response() 87         if response.get(&#39;status_code&#39;) == 254: 88             print("Passed authentication!") 89             self.user = user 90             return True 91         else: 92             print(data.get(&#39;status_msg&#39;)) 93         print(&#39;response:&#39;,data) 94  95  96     def __md5_required(self,cmd_list): 97         &#39;&#39;&#39;检测命令是否需要进行MD5验证&#39;&#39;&#39; 98         if &#39;--md5&#39; in cmd_list: 99             return True100 101 102     def show_progress(self,total):103         &#39;&#39;&#39;进度条&#39;&#39;&#39;104         received_size = 0105         current_percent = 0106         while received_size < total:107             if int((received_size / total) * 100) > current_percent:108                 print(">",end='',flush=True)109                 current_percent = int((received_size / total) * 100)110             new_size = yield111             received_size += new_size112 113 114     def send_response(self,status_code,data=None):115         '''向服务器端返回数据'''116         response = {'status_code': status_code, 'status_msg':STATUS_CODE[status_code]}117         if data:118             response.update(data)119         self.sock.send(json.dumps(response).encode())120 121 122     def get_response(self):123         '''得到服务器端回复结果'''124         data = self.sock.recv(1024)125         data = json.loads(data.decode())126         return data127 128 129     def _get(self,cmd_list):130         '''下载文件'''131         print("get--",cmd_list)132         if len(cmd_list) == 1:133             print("no filename follows...")134             return135         data_header = {136             'action':'get',137             'filename':cmd_list[1]138         }139         if self.__md5_required(cmd_list):140             data_header['md5'] = True141 142         self.sock.send(json.dumps(data_header).encode())143         response = self.get_response()144         print(response)145         try:146             if response["status_code"] == 257:#ready to receive147                 self.sock.send(b'1') #send confirmation to server148                 base_filename = cmd_list[1].split('/')[-1]149                 received_size = 0150                 file_obj = open(base_filename,'wb')151                 if self.__md5_required(cmd_list):152                     md5_obj = hashlib.md5()153                     progress = self.show_progress(response['file_size']) #generator154                     progress.__next__()155                     while received_size < response[&#39;file_size&#39;]:156                         data = self.sock.recv(4096)157                         received_size += len(data)158                         try:159                             progress.send(len(data))160                         except StopIteration as e:161                             print("100%")162                         file_obj.write(data)163                         md5_obj.update(data)164                     else:165                         print("-----file rece done-----")166                         file_obj.close()167                         md5_val = md5_obj.hexdigest()168                         md5_from_server = self.get_response()169                         if md5_from_server[&#39;status_code&#39;] == 258:170                             if md5_from_server[&#39;md5&#39;] == md5_val:171                                 print("%s 文件一致性校验成功!"% base_filename)172                         print(md5_val,md5_from_server)173 174                 else:175                     progress = self.show_progress(response[&#39;file_size&#39;])  # generator176                     progress.__next__()177                     while received_size < response[&#39;file_size&#39;]:178                         data = self.sock.recv(4096)179                         received_size += len(data)180                         file_obj.write(data)181                         try:182                             progress.send(len(data))183                         except StopIteration as e:184                             print("100%")185                     else:186                         print("-----file rece done-----")187                         file_obj.close()188             else:189                 print(STATUS_CODE[response["status_code"]])190         except Exception as e:191             base_file_size = os.path.getsize(base_filename)192             with open(&#39;data\\breakpoint&#39;, &#39;wb&#39;) as br_po:193                 data_header[&#39;action&#39;] = &#39;breakpoint&#39;194                 data_header[&#39;breakpoint&#39;] = base_file_size195                 br_po.write(json.dumps(data_header).encode())196 197 198     def _put(self,cmd_list):199         &#39;&#39;&#39;上传文件&#39;&#39;&#39;200         print("put--", cmd_list)201         if len(cmd_list) == 1:202             print("no filename follows...")203             return204         data_header = {205             &#39;action&#39;: &#39;put&#39;,206             &#39;filename&#39;: cmd_list[1]207         }208         if self.__md5_required(cmd_list):209             data_header[&#39;md5&#39;] = True210 211         self.sock.send(json.dumps(data_header).encode())212         if os.path.isfile(cmd_list[1]):213             file_obj = open(cmd_list[1], &#39;rb&#39;)214             file_size = os.path.getsize(cmd_list[1])215             self.send_response(257, data={&#39;file_size&#39;: file_size})216             self.sock.recv(1)  # 等待服务器端确认217             if self.__md5_required(cmd_list):218                 md5_obj = hashlib.md5()219                 progress = self.show_progress(file_size)  # generator220                 progress.__next__()221                 for line in file_obj:222                     self.sock.send(line)223                     try:224                         progress.send(len(line))225                     except StopIteration as e:226                         print("100%")227                     md5_obj.update(line)228                 else:229                     file_obj.close()230                     md5_val = md5_obj.hexdigest()231                     md5_from_server = self.get_response()232                     if md5_from_server[&#39;md5&#39;] == md5_val:233                             print("%s 文件一致性校验成功!"% cmd_list[1])234                     self.send_response(258, {&#39;md5&#39;: md5_val})235                     print("send file done...")236             else:237                 progress = self.show_progress(file_size)  # generator238                 progress.__next__()239                 for line in file_obj:240                     self.sock.send(line)241                     try:242                         progress.send(len(line))243                     except StopIteration as e:244                         print("100%")245                 else:246                     file_obj.close()247                     print("send file done...")248         else:249             print(256)250 251 252     def _ls(self,*args,**kwargs):253         &#39;&#39;&#39;获取当前目录下的所有文件&#39;&#39;&#39;254         print(&#39;ls&#39;.center(30,&#39;-&#39;))255         data_header = {256             &#39;action&#39;: &#39;ls&#39;,257         }258         self.sock.send(json.dumps(data_header).encode())259         ls_val = self.sock.recv(1024)260         ls_val = json.loads(ls_val.decode())261         for obj in ls_val:262             print(obj)263 264 265     def _cd(self,cmd_list):266         &#39;&#39;&#39;改变工作目录&#39;&#39;&#39;267         print("cd--", cmd_list)268         if len(cmd_list) == 1:269             cmd_list.append(&#39;&#39;)270         data_header = {271             &#39;action&#39;: &#39;cd&#39;,272             &#39;path&#39;: cmd_list[1]273         }274         self.sock.send(json.dumps(data_header).encode())275         server_path = self.sock.recv(1024)276         server_path = json.loads(server_path.decode())277         if server_path == 259 :278             print("%s >" % cmd_list[1],end='')279 280 281     def _breakpoint(self,*args,**kwargs):282         '''断点续传'''283         with open('data\\breakpoint', 'rb') as br_po:284             data_header = json.loads(br_po.read().decode())285             br_po.close()286         if data_header:287             print(data_header)288             self.sock.send(json.dumps(data_header).encode())289             response = self.get_response()290             try:291                 if response["status_code"] == 257:  # ready to receive292                     self.sock.send(b'1')  # send confirmation to server293                     base_filename = data_header['filename'].split('/')[-1]294                     received_size = data_header['breakpoint']295                     file_obj = open(base_filename, 'ab')296                     file_obj.seek(data_header['breakpoint'])297                     if self.__md5_required(data_header):298                         md5_obj = hashlib.md5()299                         progress = self.show_progress(response['file_size'])  # generator300                         progress.__next__()301                         while received_size < response[&#39;file_size&#39;]:302                             data = self.sock.recv(4096)303                             received_size += len(data)304                             try:305                                 progress.send(len(data))306                             except StopIteration as e:307                                 print("100%")308                             file_obj.write(data)309                             md5_obj.update(data)310                         else:311                             print("-----file rece done-----")312                             file_obj.close()313                             md5_val = md5_obj.hexdigest()314                             md5_from_server = self.get_response()315                             if md5_from_server[&#39;status_code&#39;] == 258:316                                 if md5_from_server[&#39;md5&#39;] == md5_val:317                                     print("%s 文件一致性校验成功!" % base_filename)318                                     with open(&#39;data\\breakpoint&#39;, &#39;wb&#39;) as br_po:319                                         br_po.write()320                             print(md5_val, md5_from_server)321 322 323 324                     else:325                         progress = self.show_progress(response[&#39;file_size&#39;])  # generator326                         progress.__next__()327                         while received_size < response[&#39;file_size&#39;]:328                             data = self.sock.recv(4096)329                             received_size += len(data)330                             file_obj.write(data)331                             try:332                                 progress.send(len(data))333                             except StopIteration as e:334                                 print("100%")335                         else:336                             print("-----file rece done-----")337                             file_obj.close()338                             with open(&#39;data\\breakpoint&#39;, &#39;wb&#39;) as br_po:339                                 br_po.write()340             except Exception as e:341                 base_file_size = os.path.getsize(base_filename)342                 with open(&#39;data\\breakpoint&#39;, &#39;wb&#39;) as br_po:343                     data_header[&#39;breakpoint&#39;] = base_file_size344                     br_po.write(json.dumps(data_header).encode())345         else:print(&#39;There is no need to transfer files..&#39;)346 347 348     def _helps(self,*args,**kwargs):349         &#39;&#39;&#39;帮助信息&#39;&#39;&#39;350         helps = &#39;&#39;&#39;351             get 文件名     #下载文件352             put 文件名     #上传文件353             ls             #获取当前目录下的所有文件354             cd             #改变工作目录355             breakpoint     #断点续传&#39;&#39;&#39;356         print(helps)357 358 359     def interactive(self):360         &#39;&#39;&#39;根据命令分配函数&#39;&#39;&#39;361         if self.authenticate():362             print(&#39;---start interactive iwth u...(helps  帮助信息)&#39;)363             while True:364                 choice = input("[%s]:" % self.user).strip()365                 if len(choice) == 0: continue366                 cmd_list = choice.split()367                 if hasattr(self, "_%s" % cmd_list[0]):368                     func = getattr(self, "_%s" % cmd_list[0])369                     func(cmd_list)370                 else:371                     print("Invalid cmd")372 373 374 375 if __name__ == &#39;__main__&#39;:376     ftp = FTPClient()377     ftp.interactive()
client端

TCP 서버 만들기
아이디어: 소켓 만들기---소켓을 로컬 주소에 바인딩---연결 듣기---무한 루프에서 TCP 클라이언트 요청에 응답(클라이언트 소켓은 이를 수신한 후 반환됩니다) ) )---TCP 데이터 수락---TCP 데이터 보내기---하위 소켓 닫기---서버 소켓 닫기
from 소켓 가져오기 *
from time import ctime

HOST = '' # 바인딩 가능함을 의미함 Any 유효한 주소
PORT = 2157
BUFSIZ = 1024 # 키워드, 크기 1k
ADR= (HOST, PORT)

tcpSerSock = 소켓(AF_INET, SOCK_STREAM) # 네트워크 기반 TCP 서버 소켓
tcpSerSock을 생성합니다.
tcpSerSock.listen(5) # 동시에 5개의 연결만 허용

while True: # 수신 대기 무한 루프
'연결 대기 중...' 인쇄
tcpCliSock, addr = tcpSerSock.accept() # 수신 , 그리고 클라이언트 소켓과 클라이언트 주소를 저장합니다
 print '...connected from:', addr

while True:
          data = tcpCliSock.recv(BUFSIZ) # 버퍼의 데이터 읽기
                         
아이디어: 클라이언트 소켓 생성; ---연결---데이터 보내기(보내기가 비어 있으면 종료)---버퍼에서 데이터 받기(수신에 실패하면 종료)---소켓 가져오기에서 클라이언트 소켓
을 닫습니다. *

HOST = 'localhost '
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)

tcpCliSock = 소켓(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)

True:
while data = raw_input('>')
데이터가 아닌 경우:
break
tcpCliSock.send(data)
data = tcpCliSock.recv(BUFSIZ)
데이터가 아닌 경우:
데이터 인쇄
tcpCliSock.close()

UDP 서버 만들기
아이디어: 소켓 만들기 --- 소켓을 로컬 주소에 바인딩 -- 데이터 수신 --- 데이터 보내기
from 소켓 import *
from time import ctime

HOST = '' # 의미는 유효한 주소를 바인딩할 수 있음
PORT = 2157
BUFSIZ = 1024 # 키워드, 크기는 1k입니다
ADR= (HOST, PORT)

udpSerSock = 소켓(AF_INET, SOCK_DGRAM)
udpSerSock.bind(ADR)

while True ; ...에서 수신하고 다음으로 반환:', addr
udpSerSock.close( )

UDP 클라이언트 만들기
아이디어: 클라이언트 소켓 만들기---데이터 보내기---데이터 받기
from 소켓 import *
from time import ctime

HOST = 'localhost' # 유효한 주소가 바인딩될 수 있음을 나타냅니다
PORT = 2157
BUFSIZ = 1024 # 키워드, 크기는 1k
ADDR= (HOST, PORT)

udpCliSock = 소켓(AF_INET, SOCK_DGRAM)

while True:
data = raw_input('>')
데이터가 아닌 경우 :
break
udpCliSock.sendto(data, ADDR)
data, ADDR = udpCliSock.recvfrom(BUFSIZ)
데이터가 아닌 경우:
break
print data
udpCliSock.close()

위 내용은 소켓을 사용하여 FTP를 구현하는 방법에 대한 자습서의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
이전 기사:urllib.request 라이브러리 사용의 기본 사항다음 기사:urllib.request 라이브러리 사용의 기본 사항

관련 기사

더보기