zoukankan      html  css  js  c++  java
  • SELECT版FTP


    功能:
    1、使用SELECT或SELECTORS模块实现并发简单版FTP
    2、允许多用户并发上传下载文件
    环境:
      python 3.5
    特性:
      select 实现并发效果
    运行:
    get 文件名 #从服务器下载文件
    put 文件名 #向服务器上传文件
    helps #帮助信息
    其他命令 #变大写返回给客户端
    主要知识点:
    os模块的应用
    json模块的运用
    select模块的运用
    socket通信
    queue数据交互
    粘包
    原理:
    这个程序通过select实现了并发,主要原理为它通过一个select()系统调用来监视多个文件描述符的数组(在linux中一切事物皆文
    件,块设备,socket连接等。),当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位(变成ready),使得进程
    可以获得这些文件描述符从而进行后续的读写操作(select会不断监视网络接口的某个目录下有多少文件描述符变成ready状态【在
    网络接口中,过来一个连接就会建立一个'文件'】,变成ready状态后,select就可以操作这个文件描述符了)。
    通过不同链接的交替,实现并发效果。
    主要代码:
    readable, writeable, exeptional = select.select(inputs,outputs,inputs) #如果没有任何fd就绪,那程序就会一直阻塞在这里
        # select中第1个参数表示inputs中发生变化的句柄放入readable。
        # select中第2个参数表示outputs中的值原封不动的传递给writeable。
        # select中第3个参数表示inputs中发生错误的句柄放入exeptional.
     
     1 import json
     2 import select
     3 import socket
     4 import queue
     5 import os
     6 
     7 
     8 os.chdir(os.pardir)
     9 server = socket.socket()
    10 server_addr = ("localhost",1000)
    11 server.bind(server_addr)
    12 server.listen(7)
    13 inputs = [server,]
    14 outputs = []
    15 message_queue ={}
    16 
    17 while True:
    18     readable,writeable,exeptional = select.select(inputs,outputs,inputs)
    19     #
    20     # 存放所有的活动
    21     for sock in readable:
    22         if sock is server:
    23             conn, client_addr = sock.accept()
    24             inputs.append(conn)
    25             message_queue[conn] = queue.Queue()    #为防阻塞,先把信息存入队列
    26         else:
    27             data = sock.recv(1024)
    28             if data:
    29                 message_queue[sock].put(data)
    30                 if sock not in outputs:
    31                     outputs.append(sock)
    32 
    33             else:
    34                 if sock in outputs:
    35                     outputs.remove(sock)
    36                 inputs.remove(sock)
    37                 del message_queue[sock]
    38     #
    39     # 存放连接信息
    40     #
    41     for sock in writeable:
    42         try:
    43             cmd = message_queue[sock].get_nowait()
    44         except queue.Empty:
    45             outputs.remove(sock)
    46         else:
    47             print("recv data:", cmd)
    48             data = json.loads(cmd.decode())
    49             if data.get('action') is not None:
    50                 #
    51                 # 上传文件
    52                 if data['action'] == 'put':
    53                     # client sends file to server
    54                     file_obj = open('data/'+data['filename'], 'wb')
    55                     received_size = 0
    56                     sock.send(b'1')
    57                     while True:
    58                         if received_size == data['size']:
    59                             break
    60                         recv_data = sock.recv(1024)
    61                         file_obj.write(recv_data)
    62                         received_size += len(recv_data)
    63                     if received_size == data['size']:
    64                         print('Successfully received file ', data['filename'])
    65                     file_obj.close()
    66                 #
    67                 # 下载文件
    68                 elif data['action'] == 'get':
    69                     if os.path.isfile(data['filename']):
    70                         data['file_size'] = os.path.getsize(data['filename'])
    71                         data['ERROR'] = '0'
    72                     else:
    73                         data['ERROR'] = '777'      #ERROR标识
    74                     sock.send(json.dumps(data).encode())
    75                     if os.path.isfile(data['filename']):
    76                         if sock.recv(1) == b'1':         #等待客户端响应,防粘包
    77                             if data['ERROR'] == '0':
    78                                 file_obj = open(data['filename'], 'rb')
    79                                 for line in file_obj:
    80                                     sock.send(line)
    81                 #
    82                 # 其他命令
    83                 else:
    84                     data['cmd'] = data['cmd'].upper()
    85                     sock.send(json.dumps(data).encode())
    86 
    87     #
    88     # 错误链接
    89     for sock in exeptional:
    90         if sock in outputs:
    91             outputs.remove(sock)
    92         inputs.remove(sock)
    93         del message_queue[sock]
    server端
    
    
     1 import json
     2 import socket
     3 import os
     4 
     5 os.chdir(os.pardir)
     6 server_address = ('localhost', 1000)
     7 sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     8 sock.connect(server_address)
     9 print('''------Welcome!!-----
    10                         (helps:帮助信息)''')
    11 while True:
    12     cmd = input(">>>").strip()
    13     cmd_list = cmd.split()
    14     #
    15     #上传文件
    16     if cmd_list[0] == 'put':
    17         if len(cmd_list) == 1:   #命令不能识别
    18             print('No filename follows after put cmd!')
    19             continue
    20         filename = 'data/'+cmd_list[1]     #将所有的文件都归入data文件夹
    21         if os.path.isfile(filename):
    22             file_obj = open(filename,'rb')
    23             base_filename = filename.split('/')[-1]
    24             data_header = {
    25                 'action':'put',
    26                 'filename':base_filename,
    27                 'size':os.path.getsize(filename)
    28             }
    29             sock.send(json.dumps(data_header).encode())
    30             if sock.recv(1) == b'1':      #防止粘包
    31                 for line in file_obj:
    32                     sock.send(line)
    33                 file_obj.close()
    34                 print('put all file..')
    35         else:
    36             print('File is not valid')
    37             continue
    38     #
    39     # 下载文件
    40     elif cmd_list[0] == 'get':
    41         if len(cmd_list) == 1:
    42             print('No filename follows after get cmd!')
    43             continue
    44         filename = 'data/'+ cmd_list[1]
    45         data_header = {
    46             'action':'get',
    47             'filename':filename,
    48             'ERROR':'0'
    49         }
    50         sock.send(json.dumps(data_header).encode())
    51         data_header = json.loads(sock.recv(1024).decode())
    52         if data_header['ERROR'] == '0':
    53             file_obj = open(data_header['filename'], 'wb')
    54             received_size = 0
    55             sock.send(b'1')
    56             while True:
    57 
    58                 if received_size == data_header['file_size']:
    59                     break
    60                 recv_data = sock.recv(1024)
    61                 file_obj.write(recv_data)
    62                 received_size += len(recv_data)
    63 
    64             print('Successfully received file ', data_header['filename'])
    65             file_obj.close()
    66     #
    67     # 帮助信息
    68     elif cmd_list[0] == 'helps':
    69         print('''
    70         put 文件名         #上传文件
    71         get 文件名         #下载文件
    72         其他命令           #返回大写''')
    73     #
    74     # 其他命令
    75     else:
    76         data_header = {
    77             'action':'else',
    78             'cmd':cmd
    79         }
    80         sock.send(json.dumps(data_header).encode())
    81         data_recv = json.loads(sock.recv(1024).decode())
    82         print(data_recv['cmd'])
    client端


  • 相关阅读:
    http与websocket(基于SignalR)两种协议下的跨域基于ASP.NET MVC--竹子整理
    让Visual Studio 2015 支持ASP.NET MVC4.0.0.1
    自定义滚动条CSS样式
    使用NuGet发布自己的类库包(Library Package)
    基于EF的数据外键关联查询
    基于EF创建数据库迁移
    用SQL命令查看Mysql数据库大小
    Python之MySQL数据操作
    Python之MySQL基础
    Python网络编程之黏包问题
  • 原文地址:https://www.cnblogs.com/liyongbin/p/7199834.html
Copyright © 2011-2022 走看看