Python案例-网络编程-socket-Ftp&多用户登录

本次Ftp的案例使用面向对象的编程方式。
其中使用反射的机制来调用本身的put和get以及cmd方法。
借用socketserver模块来实现多用户登录。具体看代码

Server端

#!/usr/bin/env python
#   --coding = utf-8
#   Author Allen Lee
import socket,subprocess,socketserver,json
#创建FtpServer,并继承socketserver 父类,来实现多用户登录
class FtpServer(socketserver.BaseRequestHandler):
    def handel(self):
        # while True:
        #     conn,addr = server.accept()
        #     print(addr)
        server_tag = False
        res = self.request.recv(1024)
        if len(res) == 0:
            return error
         #使用json格式化接收client传来的用户信息
        userinfo = json.loads(str(res,encoding='utf-8'))
        #此处用了伪代码,意为进行用户验证
        if userinfo[0].get('username') == 'username' and userinfo[0].get('password') == 'password':
            server_tag = True
            return ok
        else:
            return error
        #通过判断标签值来进行权限检验
        while server_tag:
            res =  self.request.recv(1024)
            reg = str(res,encoding='utf-8')
            #此处使用反射原理,来依次调用本身的上传、下载、命令行方法
            if reg.startswith('put'):
                if hasattr(self,put):
                    func = getattr(self,server_put)
                    func(reg)
            if reg.startswith('get'):
                if hasattr(self,get):
                    func = getattr(self,server_get)
                    func(reg)
            if reg.startswith('cmd'):
                if hasattr(self,cmd):
                    func = getattr(self,server_cmd)
                    func(reg)
    #以下为具体方法内容
    def server_put(self):
        pass

    def server_get(self):
        pass

    def server_cmd(self):
        while True:
            try:
                res_data = self.request.recv(1024)
                res_signal = str(res_data,encoding='utf-8')
                if len(res_data) == 0 :break
                #通过匹配‘put’关键字来确定执行put相关代码
                elif res_signal.startswith('put'):
                    pass

                #通过匹配‘get’关键来执行上传相关代码
                elif res_signal.startswith('get'):
                    pass
                #否则将当作正常命令来执行
                else:
                    ret = subprocess.Popen(res_signal,shell=True,stdout=subprocess.PIPE)
                    res_msg = ret.stdout.read()
                    if len(res_msg) == 0:
                        send_data = 'cmd_err'
                    else:
                        send_data = str(res_msg,encoding='gbk')
                    print(send_data, type(send_data))
                    #通知客户端,本次包的总大小,并打上‘ready’的signal,让client来抓取,注意这里用“|”为分隔符
                    send_tag = 'ready|%d' %(len(res_msg))
                    self.request.send(bytes(send_tag,encoding='utf-8'))
                    #为了调试代码进度所添加的输出
                    print(send_tag)
                    #cilent在收到‘ready’的标签后,给服务端回一个‘start’,通知服务端可以发包
                    recv_data = self.request.recv(1024)
                    recv_tag = str(recv_data,encoding='utf-8')
                    #在服务端接收到来时client的确认信息之后,则开始发送client请求的信息;
                    if recv_tag == 'start':
                        self.request.send(bytes(send_data,encoding='utf-8'))
                    else:
                        self.request.send(bytes('do not receive the start signal',encoding='utf-8'))
            except Exception:
                break
            conn.close()



if __name__ == '__main__':
    #调用socketserver的ThreadingTCPServer,来实现多线程
    server = socketserver.ThreadingTCPServer(('127.0.0.1',8088),FtpServer.run())
    server.serve_forever()

Client端:

#!/usr/bin/env python
#   --coding = utf-8
#   Author Allen Lee
import socket
from lib import commons
#创建FtpClient类
class FtpClient:
    #在构造函数中初始化client连接server的功能
    def __init__(self,ip,port):
        self.ip = ip
        self.port = port
        self.client = socket.socket()
        self.client.connect((self.ip,self.port))
        self.tag = False
        #验证用户名密码,输错有三次机会,根据server端返回的信息来判断是否验证成功
        for i in range(3):
            username = input('please input your username:')
            passwd = input('please input your passwd:')
            password = commons.md5(passwd)
            userinfo = {"username":username,"password":password }
            self.client.send(bytes(json.dumps(userinfo),encoding='utf-8'))
            ret = self.client.recv(1024)
            res_check = str(ret,encoding='utf-8')
            if res_check == 'ok':
                self.tag = True
                break
            else:
                continue
            print("your username or passwd is wrong")
            self.client.close()
        #循环使用进程
        while True:
            send_signal = input('>> :').strip()
            if len(send_signal) == 0:continue
            #权限验证
            while self.tag:
                if hasattr(self,send_signal):
                    func = getattr(self,send_signal)
                else:
                    func = getattr(self,'cmd')
                    func(args)

    def put(self,reg):
        # file_path =
        pass
    def get(self,reg):
        pass

    def cmd(self,reg):
        while True:
            res_firt = self.client.recv(1024)
            send_data = reg

            send_msg = bytes(send_data,encoding='utf-8')
            self.client.send(send_msg)
            res_data = self.client.recv(1024)
            res_tag = str(res_data,encoding='utf-8')
            #client接收并解析服务端发回的信息是否是ready开头的,以此判断是否要开始发包了
            if res_tag.startswith('ready'):
                #将ready后的数字传给res_total,用于之后的信息回显,同理也可以来做一个进度条的显示功能
                res_total = int(res_tag.split('|')[1])
                #初始化当前接收的信息节点数值
                res_now = 0
                # cilent在收到‘ready’的标签后,给服务端回一个‘start’,通知服务端可以发包
                client.send(bytes('start',encoding='utf-8'))
                #在当前信息值不大于总值的情况下,循环获取并打印服务端发过来的信息
                while res_now < res_total:
                    #设置recv最小接收信息单元 的字节数
                    res_data = self.client.recv(1024)
                    res_now += len(res_data)
                    print('total:%s----now:%s'%(res_total,res_now))
                    print(str(res_data,encoding='utf-8'))

    def exit(self):
        self.tag = False
        client.close()

if __name__ == '__main__':
    client = FtpClient('127.0.0.1',8088)
    client()

你可能感兴趣的:(Python案例,python开发之路)