第八(类进阶及网络编程)

一、抽象类与接口

1.1.java有interface关键字来实现接口

在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。

/* 文件名 : Animal.java */
interface Animal {
   public void eat();
   public void travel();
}
/* 文件名 : MammalInt.java */
public class MammalInt implements Animal{
 
   public void eat(){
      System.out.println("Mammal eats");
   }
 
   public void travel(){
      System.out.println("Mammal travels");
   } 
 
   public int noOfLegs(){
      return 0;
   }
 
   public static void main(String args[]){
      MammalInt m = new MammalInt();
      m.eat();
      m.travel();
   }
}

interface定义好eat和trave,当类实现接口,就必须实现接口的所有方法,也就是这两个方法,那么python如何实现?

class Interface:
    def read(self):
        pass

    def write(self):
        pass


class Sata(Interface):
    def read(self):
        print("read file type: sata")

    def write(self):
        print("write file type: sata")


class Files(Interface):
    def read(self):
        print("read file type: filesß")

    def write(self):
        print("write file type: files")


class Process(Interface):
    def read(self):
        print("read file type: process")

    def write(self):
        print("write file type: process")

这样是实现了,但是好像没多大意义,父类完全没必要存在,也没有起到限制作用,这里就要用到抽象类。python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。

import abc  #导入模块
class Interface(metaclass=abc.ABCMeta):
    @abc.abstractmethod  #定义抽象类方法,无须实现
    def read(self):
        pass

    @abc.abstractmethod  #定义抽象类方法,无须实现
    def write(self):
        pass


class Sata(Interface):
    def duqu(self):
        pass

    def write(self):
        print("write file type: sata")

实例化报错:

不能实例化,因为缺少抽象方法,正确如下: 

import abc  #导入模块
class Interface(metaclass=abc.ABCMeta):
    @abc.abstractmethod  #定义抽象类方法,无须实现
    def read(self):
        pass

    @abc.abstractmethod  #定义抽象类方法,无须实现
    def write(self):
        pass


class Sata(Interface):
    def read(self):
        print("read file type: sata")

    def write(self):
        print("write file type: sata")


class Files(Interface):
    def read(self):
        print("read file type: files")

    def write(self):
        print("write file type: files")


class Process(Interface):
    def read(self):
        print("read file type: process")

    def write(self):
        print("write file type: process")

s=Sata()
f=Files()
p=Process()

 二、多态及多态性

 多态就是事物具有多种形态

import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass

class Mankind(Animal): #动物形态一:人类
    def talk(self):
        print("Man is saying")

class Pigeon(Animal): #动物形态二:鸽子
    def talk(self):
        print("Pigeon is singing")

class Rabbit(Animal): #动物形态三:兔子
    def talk(self):
        print("Rabbit is huhu")

多态性

有时称多态绑定(继承前提下使用)

多态性是不考虑实例类型而使用实例

在面向对象方法中一般是这样表述多态性:
向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),不同的对象在接收时会产生不同的行为(即方法)。
也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。

比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同

 如下例子:

import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass

class Mankind(Animal): #动物形态一:人类
    def talk(self):
        print("Man is saying")

class Pigeon(Animal): #动物形态二:鸽子
    def talk(self):
        print("Pigeon is singing")

class Rabbit(Animal): #动物形态三:兔子
    def talk(self):
        print("Rabbit is huhu")

def func(obj):
    obj.talk()

M1=Mankind()
P1=Pigeon()
R1=Rabbit()
func(M1)
func(P1)
func(R1)

运行结果:

多态增加了程序的灵活性和扩展性。

三、封装

隐藏:

class Foo:
    __N=888
    def __init__(self,name):
        self.__Name=name

    def __f1(self):
        print('is f1')

    def f2(self):
        self.__f1()

f=Foo('egon')
# print(f.__N)  #访问不到
# f.__f1()  #访问不到
# print(f.__Name) #访问不到
f.f2()   #可以访问到f2,f2可以访问到__f1,所以结果是'is f1'

#这种隐藏需要注意的问题

  • 这种隐藏只是一种语法上变形操作,并不会将属性真正隐藏起来
    print(Foo.__dict__) #{'__module__': '__main__', '_Foo__N': 888, '__init__': <function Foo.__init__ at 0x107aad1e0>, '_Foo__f1': <function Foo.__f1 at 0x107aad378>, 'f2': <function Foo.f2 at 0x107aad400>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
    #刚才隐藏的属性变形了,如:_Foo__N,但是外部还可以通过这种方式访问
    print(f._Foo__Name) #egon
  • 这种语法级别的变形,是在类定义阶段发生的,并且只在类定义阶段发生
    class Foo:
        __N=888 #_Foo__N
        def __init__(self,name):
            self.__Name=name #_Foo__Name
    
        def __f1(self): #_Foo__f1
            print('is f1')
    
        def f2(self):
            self.__f1() #_Foo__f1()
    Foo.__x=1234567
    print(Foo.__x) #没有发生变形,可以直接访问
    # 1234567

 示例看隐藏的使用

class Foo:
    def f1(self):
        print("this is Foo's f1")

    def f2(self):
        self.f1()

class Bar(Foo):
    def f1(self):
        print("this is bar's f1")

b1=Bar()
b1.f2()

调用结果:

这是之前的结果,如果想调用Foo的f1呢,这里就需要用到隐藏了,如下:

class Foo:
    def __f1(self): #_Foo__f1
        print("this is Foo's f1")

    def f2(self):
        self.__f1() #_Foo_f1()

class Bar(Foo):
    def __f1(self): #_Bar__f1
        print("this is bar's f1")

b1=Bar()
b1.f2()

结果:

这是因为隐藏在定义阶段以及变形,所以访问的f1不会再覆盖困扰了。

封装数据属性

class People:
    def __init__(self,name,age):
        self.__Name = name
        self.__Age = age

    def tell_info(self):
        print("name is :%s \nage is: %s" %(self.__Name,self.__Age))

p1=People('ckl',22)
p1.tell_info()

结果:

可以通过一个tell_info接口来访问内部隐藏属性的内容,但是如果要修改呢?

class People:
    def __init__(self,name,age):
        self.__Name = name
        self.__Age = age

    def tell_info(self):
        print("name is :%s \nage is: %s" %(self.__Name,self.__Age))

    def set_info(self,x,y):
        if not isinstance(x,str):
            raise TypeError("%s must be a str type" %x)
        if not isinstance(y,int):
            raise TypeError("%s must be a int type" %y)
        self.__Name = x
        self.__Name = y

p1=People('ckl',22)
p2=People('ckl',24)
p1.tell_info()
p2.tell_info()

结果:

属性隐藏起来后,内部可以用,外部不可以,但是通过增加一个接口的方式,外部也可以调用。并且在接口上可以增加任何控制逻辑来控制接口运行

例子中,控制姓名为字符串,年龄为数字类型。

封装函数属性

隔离复杂度

#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
#对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
#隔离了复杂度,同时也提升了安全性

class ATM:
    def __card(self):
        print('插卡')
    def __auth(self):
        print('用户认证')
    def __input(self):
        print('输入取款金额')
    def __print_bill(self):
        print('打印账单')
    def __take_money(self):
        print('取款')

    def withdraw(self):
        self.__card()
        self.__auth()
        self.__input()
        self.__print_bill()
        self.__take_money()

a=ATM()
a.withdraw()

 四、静态属性property

property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

BMI指数成人的BMI数值:

过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
  体质指数(BMI)=体重(kg)÷身高^2(m)
  EX:70kg÷(1.75×1.75)=22.86
class Man:
    def __init__(self,name,weight,hight):
        self.name = name
        self.weight = weight
        self.hight = hight

    @property
    def bmi(self):
        print(self.weight/(self.hight*self.hight))

m1=Man('ckl',73,1.76)
m1.bmi

结果:

通过property属性,可以使访问函数方法像访问属性一样,注意,我体脂指标正常。

property属性的修改和删除

class Foo:
    def __init__(self,x):
        self.__Name = x

    @property
    def name(self):
        return self.__Name

    @name.setter #修改,必须name是property
    def name(self,val):
        if not isinstance(val,str):
            raise TypeError
        self.__Name = val

    @name.deleter #删除,必须name是property
    def name(self):
        print("Start to delete....")
        del self.__Name

f=Foo('ckl')
print(f.name)  #ckl
f.name = 'kkk'
print(f.name)  #kkk
del f.name
print(f.name)  

五、反射

反射就是通过字符串的形式获取方法或属性

反射有4个内置函数分别为:getattr、hasattr、setattr、delattr,获取、检查、设置、删除

class Foo:
    x=1
    def __init__(self,name):
        self.name = name

    def f1(self):
        print('from f1')


f=Foo('ckl')
# print(f.__dict__) #{'name': 'ckl'}

#检查name是否存在
print(hasattr(f,'name')) #True
print(hasattr(f,'f1')) #True
print(hasattr(f,'x')) #True

#获取name
print(getattr(f,'name')) #ckl
print(getattr(f,'abc',None)) #没有则返回None,否则会报错
fc=getattr(f,'f1')
fc()  # from f1

#设置name的值
setattr(f,'name','wukaka')
print(f.name) #wukaka

#删除属性
delattr(f,'name')
print(f.__dict__) #{}

 反射ftp小示例,通过用户输入,运行相关方法

class FtpServer:
    def __init__(self,host,port):
        self.host = host
        self.port = port

    def run(self):
        while True:
            cmd = input(':>> ').strip()
            if not cmd:
                continue
            if hasattr(self,cmd):
                fc1=getattr(self,cmd)
                fc1()

    def get(self):
        print("get func ...")

    def put(self):
        print("put func ...")

f1=FtpServer('11.1.1.1','21')
f1.run()

运行结果:

六、item

通过字典的形式去访问对象属性

class Mankind:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __getitem__(self, item):
        print('getitem ----->>>')
        return getattr(self,item)

    def __setitem__(self, key, value):
        print('setitem ----->>>')
        setattr(self,key,value)

    def __delitem__(self, key):
        print('delitem ----->>>')
        delattr(self,key)


m=Mankind('wukaka',22)
print(m['name'])
# getitem ----->>>
# wukaka

m['name'] = 'nianhui' #setitem ----->>>
print(m['name'])
# getitem ----->>>
# nianhui

del m['name'] #getitem ----->>>
print(m.__dict__) #{'age': 22}

 只有字典形式访问属性,才能触发定义的方法。

__str__

class Mankind:
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender

    def __str__(self): #在对象被打印时触发
        return ("name :%s,age :%s,gender: %s"%(self.name,self.age,self.gender))

M1=Mankind('ckl',22,'male')
M2=Mankind('wz',19,'Female')
print(M1)
print(M2)

结果:

“__del__”就是一个析构函数了,当使用del 删除对象时,会调用他本身的析构函数,另外当对象在某个作用域中调用完毕,在跳出其作用域的同时析构函数也会被调用一次,这样可以用来释放内存空间。

__del__()也是可选的,如果不提供,则Python 会在后台提供默认析构函数

如果要显式的调用析构函数,可以使用del关键字,方式如下:
del对象名
class Foo:
    def __init__(self,name):
        self.name = name
        print("%s begin to ...." %self.name)

    def __del__(self):
        print("When run this,it's mean that you go die")

f=Foo('wukaka')
del f
print("has been deleted.....")

结果:

七、网络编程

TCP通信模型

模拟tcp通信示例

服务端:

import socket

#准备服务端套接字
cklServer=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#绑定地址和端口
cklServer.bind(('127.0.0.1',9090))

#建立半链接,5为等待半链接的队列
cklServer.listen(5)

#等待建立链接
conn,client_addr=cklServer.accept() #tcp链接;客户端地址端口等
print("tcpserver",conn)
print("tcpserver",client_addr)

#建立链接,接收消息
client_data = conn.recv(1024)
print("from client msg: ",client_data)

#发送消息
conn.send(client_data.upper())

#关闭链接
conn.close()

#关闭server端
cklServer.close()

客户端:

import socket

#准备客户端套接字
cklClient = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#与服务的建立链接
cklClient.connect(('127.0.0.1',9090))

#向服务端发送消息
cklClient.send('kitty'.encode('utf-8'))

#接收服务端的消息
server_data = cklClient.recv(1024)
print('from server msg:',server_data)

#关闭客户端
cklClient.close()

服务端结果:

客户端结果:

上面问题:

1.只能接收一次消息。

2.运行服务端有时候会出现地址被占用(因为socket还未完全被释放)

改良如下:

服务端:

#服务端

import socket

cklServer=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#增加对地址的重用,防止socket还未被释放的情况
cklServer.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
cklServer.bind(('127.0.0.1',9090))
cklServer.listen(5)

conn,client_addr=cklServer.accept()

#循环接收与发送文件,通讯循环
while True:
    client_data = conn.recv(1024)
    print(client_data)
    conn.send(client_data.upper())


conn.close()
cklServer.close()

客户端:

import socket

cklClient = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
cklClient.connect(('127.0.0.1',9090))

#循环接收发送文件
while True:
    msg = input('>> ').strip()
    #内容为空则继续
    if not msg:
        continue
    cklClient.send(msg.encode('utf-8'))
    server_data = cklClient.recv(1024)
    print(server_data.decode('utf-8')) #对于接收的内容进行解码
cklClient.close()

服务端运行:(结果基于客户端已经发送)

客户端运行:

新问题:

1.客户端如果断开,服务端默认接收空,所以进入死循环,不停发送空

2.如果有多个客户端,其它客户端无法进来

服务端:

import socket

cklServer=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
cklServer.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
cklServer.bind(('127.0.0.1',9090))
cklServer.listen(5)

while True: #循环链接
    conn,client_addr=cklServer.accept()
    print(conn)

    while True: #循环通信
        client_data = conn.recv(1024)
        if not client_data: #如果内容为空,则终止,mac和linux
            break
        print(client_data)
        conn.send(client_data.upper())


conn.close()
cklServer.close()

客户端不变,运行两个相同的客户端:

运行服务器:

...

运行客户端1:

服务器端返回:

建立链接,并且返回客户端1内容

运行客户端2:(处于等待状态)

关闭客户端1

再看客户端2:

服务端返回:

与客户端2建立连接,并返回内容。

 模拟ssh

服务端:

import socket
import subprocess

cklServer=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
cklServer.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
cklServer.bind(('127.0.0.1',9090))
cklServer.listen(5)

while True:
    conn,client_addr=cklServer.accept()

    while True:
        client_cmd = conn.recv(1024)
        if not client_cmd:
            break
        print(client_cmd)
        #执行命令
        cmd_result = subprocess.Popen(client_cmd,shell=True,
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.PIPE)
        #得到命令正常输出
        stdout = cmd_result.stdout.read()
        #得到命令错误输出
        stderr = cmd_result.stderr.read()
        #发送命令结果到客户端
        conn.send(stdout+stderr)


conn.close()
cklServer.close()

客户端:

import socket

cklClient = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
cklClient.connect(('127.0.0.1',9090))


while True:
    cmd = input('>> ').strip()

    if not cmd:
        continue
    cklClient.send(cmd.encode('utf-8'))
    server_data = cklClient.recv(1024)
    print(server_data.decode('utf-8'))

cklClient.close()

运行服务端:

...

运行客户端:

 

tcp粘包

如上实现,当我继续输入命令?输入结果如下:

ls命令结果竟然是上条命令的结尾,这是为什么?因为上调命令的结果没有接受完毕,第二次继续接受上调命令的结果,这就是粘包现象,如何解决?

这里用到python另外一个模块,struct,可以把一个类型,转成固定长度的bytes

使用示例:

优化的服务端:

import socket
import subprocess
import struct

cklServer=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
cklServer.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
cklServer.bind(('127.0.0.1',9090))
cklServer.listen(5)

while True:
    conn,client_addr=cklServer.accept()

    while True:
        client_cmd = conn.recv(1024)
        if not client_cmd:
            break
        print(client_cmd)

        cmd_result = subprocess.Popen(client_cmd,shell=True,
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.PIPE)

        stdout = cmd_result.stdout.read()
        stderr = cmd_result.stderr.read()
        #设定发送头部,内容为实际内容,长度转为固定长度4
        header=struct.pack('i',len(stdout+stderr))
        #发送头部
        conn.send(header)
        #发送实际内容
        conn.send(stdout+stderr)
        # conn.send(stdout+stderr)


conn.close()
cklServer.close()

优化客户端:

import socket
import struct

cklClient = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
cklClient.connect(('127.0.0.1',9090))


while True:
    cmd = input('>> ').strip()

    if not cmd:
        continue
    cklClient.send(cmd.encode('utf-8'))
    #设定接受头部长度为4
    header = cklClient.recv(4)
    #反解头部
    head_data = struct.unpack('i',header)
    #获取头部的实际长度
    data_length = head_data[0]
    #设定接受内容为空
    recv_data = ''

    #循环接受内容,每次1024,直到全部接受完毕
    while len(recv_data) < data_length:
        every_recv = cklClient.recv(1024).decode('utf-8')
        recv_data += every_recv
    print(recv_data)
    # print(server_data.decode('utf-8'))

cklClient.close()

运行服务端:

运行客户端:

 

没有出现粘包现象。

socketserver 多并发

之前的程序都是单个客户端,通过socketserver可以实现多客户端并发

服务端:

import socketserver

class CklTcphandler(socketserver.BaseRequestHandler):
    def handle(self): #通信循环
        print(self)
        while True:
            data=self.request.recv(1024)
            self.request.send(data.upper())


if __name__ == '__main__':
    #取代连接循环
    server = socketserver.ThreadingTCPServer(('127.0.0.1',8090),CklTcphandler)
    server.serve_forever()

客户端:

import socket
import struct

cklClient = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
cklClient.connect(('127.0.0.1',8090))


while True:
    msg = input('>> ').strip()

    if not msg:
        continue
    cklClient.send(msg.encode('utf-8'))
    server_data = cklClient.recv(1024)
    print(server_data.decode('utf-8'))

cklClient.close()

运行服务端:

...

运行客户端1:

运行客户端2:

服务端:

 模拟ftp

一个失败的服务端:

import socketserver
import hashlib
import struct
import json
import os

current_user = {'user': None}

class ftpTcphandler(socketserver.BaseRequestHandler):
    def handle(self):
        # print(self)
        # while True:
        #     data=self.request.recv(1024)
        #     self.request.send(data.upper())
        #self.auth()
        self.run()

    def auth(self):
        if current_user['user']:
            print("need not to login")
            # return self()

        with open('db.txt', encoding='utf-8') as f:
            user_dic = eval(f.read())

        count=0
        while count < 3:
            #接受用户名和密码
            name_pass = self.request.recv(1024).decode('utf-8')
            #将json格式内容解为字典
            name_pass_dict = json.loads(name_pass)

            name = name_pass_dict['user']
            password = name_pass_dict['pass']

            #加密存储的密码并加盐
            dic_pass = hashlib.sha256('ckl168'.encode('utf8'))
            dic_pass.update(user_dic[name].encode('utf8'))
            store_pass = dic_pass.hexdigest()

            if name in user_dic and password == store_pass:
                # res = self()
                current_user['user'] = name
                # return res
                login_msg= "login successful."
                self.request.send(login_msg.encode('utf-8'))
                break
            else:
                if count == 2:
                    logf_msg1="you have tried too many times.you will quit"
                    self.request.send(logf_msg1.encode('utf-8'))
                else:
                    logf_msg2="username or password is wrong"
                    self.request.send(logf_msg2.encode('utf-8'))
            count+=1
            print(count)

    def put(self,fmsg):
        #获取总文件大小
        all_recv_length = fmsg['filesize']
        print("start to receiving....")
        recv_fsize = 0
        while recv_fsize < all_recv_length:
            with open(fmsg['filename'], 'ab') as fwrite:
                each_recv = self.request.recv(200)
                print(each_recv)
                fwrite.write(each_recv)
            #获取当前文件大小
            recv_fsize = os.path.getsize(fmsg['filename'])
            print(recv_fsize)
            print(all_recv_length)
        print('-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x')

    def run(self):
        while True:
            msg_recv = self.request.recv(1024).decode('utf-8')
            if not msg_recv:
                break

            msg_dict = json.loads(msg_recv)
            print(msg_dict)

            client_cmd = msg_dict['act']
            print(client_cmd)
            if client_cmd == 'put':
                self.put(msg_dict)


if __name__ == '__main__':
    server = socketserver.ThreadingTCPServer(('127.0.0.1',8022),ftpTcphandler)
    server.serve_forever()

一个失败的客户端:

import socket
import struct
import json
import re
import sys
import hashlib
import os

cmd_list = ['put','get','ls']
class CklFtpClient:
    address_family = socket.AF_INET
    socket_type = socket.SOCK_STREAM
    allow_reuse_address = False
    max_packet_size = 8192
    coding = 'utf-8'
    request_queue_size = 5

    def __init__(self,server_address,connect=True):
        self.server_address = server_address
        self.socket = socket.socket(self.address_family,self.socket_type)
        self.socket.settimeout(3)

        if connect:
            try:
                self.client_connect()
            except:
                self.client_close()
                raise

    def client_connect(self):
        self.socket.connect(self.server_address)

    def client_close(self):
        self.socket.close()

    def auth(self):
        print("Welcome login ckl ftp.")
        ask_tag=1
        user_dict = {}
        while ask_tag:
            username = input("please input your login name: ")
            password = input("please input your password: ")

            #用户名密码加密并加盐
            codepass = hashlib.sha256('ckl168'.encode('utf-8'))
            codepass.update(password.encode('utf-8'))
            password = codepass.hexdigest()

            #用户名和密码加入到字典
            user_dict['user'] = username
            user_dict['pass'] = password
            print(user_dict)

            #将字典转为json格式
            js_user_dict = json.dumps(user_dict)
            self.socket.send(js_user_dict.encode('utf-8'))
            data=self.socket.recv(1024).decode('utf-8')
            print(data)
            suc_str = 'successful'
            fail_str = 'quit'
            if suc_str in data:
                ask_tag = 0

            if fail_str in data:
                self.socket.close()
                sys.exit(1)

    def put(self,fjson,flist):
        #发送文件信息json
        self.socket.send(fjson.encode('utf-8'))
        print("start to upload file ...")
        with open(flist[1],'rb') as fread:
            for line in fread:
                self.socket.send(line)
            else:
                print("upload success.")

    def run(self):
        while True:
            cmd = input('>> ').strip()
            if not cmd:
                continue
            #命令列表,第一个是命令,第二个是文件路径
            cmd_input_list = cmd.split(' ')
            #生成空文件信息字典
            cmd_input_dict = {}

            try:
                if cmd_input_list[0] not in cmd_list:
                    print('wrong: command not found')

                if cmd_input_list[0] == 'put':
                    if not os.path.exists(cmd_input_list[1]):
                        print('file is not found')
                    else:
                        print('--------------------')
                        fsize = os.path.getsize(cmd_input_list[1])

                        #获取文件md5值
                        put_md5 = hashlib.md5()
                        with open(cmd_input_list[1],'rb') as fread:
                            for line in fread:
                                put_md5.update(line)
                        f_md5 = put_md5.hexdigest()
                        #获取文件名
                        file_name = os.path.basename(cmd_input_list[1])
                        cmd_input_dict['act'] = cmd_input_list[0]
                        cmd_input_dict['filename'] = file_name
                        cmd_input_dict['filesize'] = fsize
                        cmd_input_dict['md5'] =  f_md5
                        #将字段转成json
                        cmd_put = json.dumps(cmd_input_dict)
                        print(cmd_put)
                        self.put(cmd_put,cmd_input_list)

                if cmd_input_list[0] == 'get':
                    pass
            except IndexError:
                print("Wrong: please choose a file.")


ftpclient=CklFtpClient(('127.0.0.1',8022))
#ftpclient.auth()
ftpclient.run()

都失败了,就没运行,哈哈

posted @ 2017-06-16 10:55  ckl893  阅读(206)  评论(0编辑  收藏  举报