python实现FTP通信软件

一 代码

1、服务端代码
import socket
import threading
import os
import struct
#用户账号、密码、主目录
#也可以把这些信息存放到数据库中
users = {'zhangsan':{'pwd':'zhangsan1234', 'home':r'c:\python 3.5'},
         'lisi':{'pwd':'lisi567', 'home':'c:\\'}}
def server(conn,addr, home):
    print('新客户端:'+str(addr))
    #进入当前用户主目录
    os.chdir(home)
    while True:
        data = conn.recv(100).decode().lower()
        #显示客户端输入的每一条命令
        print(data)
        #客户端退出
        if data in ('quit', 'q'):
            break
        #查看当前文件夹的文件列表
        elif data in ('list', 'ls', 'dir'):
            files = str(os.listdir(os.getcwd()))
            files = files.encode()
            conn.send(struct.pack('I', len(files)))
            conn.send(files)
        #切换至上一级目录
        elif ''.join(data.split()) == 'cd..':
            cwd = os.getcwd()
            newCwd = cwd[:cwd.rindex('\\')]
            #考虑根目录的情况
            if newCwd[-1] == ':':
                newCwd += '\\'
            #限定用户主目录
            if newCwd.lower().startswith(home):
                os.chdir(newCwd)
                conn.send(b'ok')
            else:
                conn.send(b'error')
        #查看当前目录
        elif data in ('cwd', 'cd'):
            conn.send(str(os.getcwd()).encode())
        elif data.startswith('cd '):
            #指定最大分隔次数,考虑目标文件夹带有空格的情况
            #只允许使用相对路径进行跳转
            data = data.split(maxsplit=1)
            if len(data) == 2 and  os.path.isdir(data[1]) \
               and data[1]!=os.path.abspath(data[1]):
                os.chdir(data[1])
                conn.send(b'ok')
            else:
                conn.send(b'error')
        #下载文件
        elif data.startswith('get '):
            data = data.split(maxsplit=1)
            #检查文件是否存在
            if len(data) == 2 and os.path.isfile(data[1]):
                conn.send(b'ok')
                fp = open(data[1], 'rb')
                while True:
                    content = fp.read(4096)
                    #发送文件结束
                    if not content:
                        conn.send(b'overxxxx')
                        break
                    #发送文件内容
                    conn.send(content)
                    if conn.recv(10) == b'ok':
                        continue
                fp.close()
            else:
                conn.send(b'no')
        #无效命令
        else:
            pass
            
    conn.close()
    print(str(addr)+'关闭连接')
#创建Socket,监听本地端口,等待客户端连接
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('', 10600))
sock.listen(5)
while True:
    conn, addr = sock.accept()
    #验证客户端输入的用户名和密码是否正确
    userId, userPwd = conn.recv(1024).decode().split(',')
    if userId in users and users[userId]['pwd'] == userPwd:
        conn.send(b'ok')
        #为每个客户端连接创建并启动一个线程,参数为连接、客户端地址、客户主目录
        home = users[userId]['home']
        t = threading.Thread(target=server, args=(conn,addr,home))
        t.daemon = True
        t.start()
    else:
        conn.send(b'error')
 
 
2、客户端代码
import socket
import sys
import re
import struct
import getpass
def main(serverIP):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((serverIP, 10600))
    userId = input('请输入用户名:')
    #使用getpass模块的getpass()方法获取密码,不回显
    userPwd = getpass.getpass('请输入密码:')
    message = userId+','+userPwd
    sock.send(message.encode())
    login = sock.recv(100)
    #验证是否登录成功
    if login == b'error':
        print('用户名或密码错误')
        return
    #整数编码大小
    intSize = struct.calcsize('I')
    while True:
        #接收客户端命令,其中##>是提示符
        command = input('##> ').lower().strip()
        #没有输入任何有效字符,提前进入下一次循环,等待用户继续输入
        if not command:
            continue
        #向服务端发送命令
        command = ' '.join(command.split())
        sock.send(command.encode())
        #退出
        if command in ('quit', 'q'):
            break
        #查看文件列表
        elif command in ('list', 'ls', 'dir'):
            loc_size = struct.unpack('I', sock.recv(intSize))[0]
            files = eval(sock.recv(loc_size).decode())
            for item in files:
                print(item)
        #切换至上一级目录
        elif ''.join(command.split()) == 'cd..':
            print(sock.recv(100).decode())
        #查看当前工作目录
        elif command in ('cwd', 'cd'):
            print(sock.recv(1024).decode())
        #切换至子文件夹
        elif command.startswith('cd '):
            print(sock.recv(100).decode())
        #从服务器下载文件
        elif command.startswith('get '):
            isFileExist = sock.recv(20)
            #文件不存在
            if isFileExist != b'ok':
                print('error')
            #文件存在,开始下载
            else:
                print('downloading.', end='')
                fp = open(command.split()[1], 'wb')
                while True:
                    print('.', end='')
                    data = sock.recv(4096)
                    if data == b'overxxxx':
                        break
                    fp.write(data)
                    sock.send(b'ok')
                fp.close()
                print('ok')
                
        #无效命令
        else:
            print('无效命令')
    sock.close()
if __name__ == '__main__':
    if len(sys.argv) != 2:
        print('Usage:{0} serverIPAddress'.format(sys.argv[0]))
        exit()
    serverIP = sys.argv[1]
    if re.match(r'^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$', serverIP):
        main(serverIP)
    else:
        print('服务器地址不合法')
        exit()
 
二 运行结果
客户端运行结果


 

猜你喜欢

转载自cakin24.iteye.com/blog/2386207