python_ importlib、断言 / socket ssh客户端(1.一次性读取 2.黏包) / socket server / FTP
在这里得感谢,老师Alex金角大王(路飞学城IT)
Python(给兄弟们挂个🔗)
python边写边更… 这张有点多,QAQ…代码写的有点乱,hhhh我就是Alex说的山炮写的代码吧/狗头/狗头
一、_ _ import _ _ / importlib、断言:
(1)_ _ import _ _的使用:(以"字符串"的形式,导入文件)
(在lib目录下,写一个aa.py,再在aa里面写一个“类”,方便调用)
class man(object):
def __init__(self,name):
self.name = name
lib = __import__("lib.aa")#这个内置方法,给予句柄,是目录文件;而不是aa
print(lib.aa.man("alex").name)#调用lib下的aa,在直接调用man,实例化姓名,属性输出
(2):一般使用importlib.import_moduel:(直接可以调用到“目录下的文件”)
import importlib
aa = importlib.import_module("lib.aa")
print(aa.man("Tom").name)
(3)“断言”:assert:(判断什么就是什么…例如:“abcd”是一段字符串)
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
assert type("abcd") is str
print("字符串无疑")
(这个“判断”,不是赋值句柄,然后print…True/Fluse;而是“阻断”后方程序)
(4)回顾一下,上节课学的,socket网络编程:建议自己写一遍…
server:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
server = socket.socket()
server.bind(("localhost",9999))#元组形式
server.listen(5)#开始监听
while True:
conn,addr = server.accept()#conn是"实例化"的一个对象,adder是client地址
#waiting“等电话阶段”
while True:
print("电话来了...")
data = conn.recv(1024)#接收的bytes类型
print(">>>",data)
if not data:break
conn.send(data.upper())#bytes类型,也可以用“upper”方法
server.close()
client:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
client = socket.socket()#创建服务端
client.connect(("localhost",9999))#连接,元组形式
while True:
msg = input(">>>:").strip()
if not msg : continue
client.send(msg.encode("utf-8"))#传输时,用bytes
client.recv(1024)#最大接收1024k
client.close()
conclude:
1.客服端:connect / send /recv
2.服务端:bind / listen / conn,addr = accpet() / recv /send
二、socket.ssh:
1.一次性读取:
(1):client传输“执行”命令:
client:
import socket
client =socket.socket()
client.connect(("localhost",9999))
while True:
msg = input(">>>:").strip()
if len(msg) ==0:continue
client.send(msg.encode("utf-8"))
recv_result = client.recv(1024)
print(recv_result.decode())#解码操作
client.close()
server:
import socket,os
server = socket.socket()
server.bind(("localhost",9999))
server.listen(5)
while True:
conn,addr =server.accept()
print("the is coming....")
while True:
data = conn.recv(1024)
print(data)
if not data:
print("client is losing。。。。")
break
cmd = os.popen(data.decode()).read()
print("指令:",cmd)#如果是错误的命令,cmd就是“空”,客服端就会一直等...“卡死”
if len(cmd) == 0:
conn.send("the input code is invailded。。。。".encode("utf-8"))
conn.send(cmd.encode("utf-8"))
print("have sending。。。")
server.close()
conclude:
1.如果是“错误”指令,server这边执行不了,cmd是空的,client就会一直等这个命令,就会卡住;就必须加个if,返回告诉client
2.还有就是指令执行结果,如果是大于8k,缓存区根本存不了,得分好几次发送;缓存区(①.满了发送 ②.到时间了,send强制发送)
(2):client"一直收"操作:
tips:
a="汉字"
print(len(a))
print(len(a.encode("utf-8")))
result:2
6
中文,编码字节lens为3;所以你“事先”的文件指令(可能含有“中文”)长度 ≠ client端接收到的bytes(字节长度);server中cmd,先encode,再len,最后send size;否则后面会报错…
server:
import socket,os
server = socket.socket()
server.bind(("localhost",9999))
server.listen(5)
while True:
conn,addr =server.accept()
print("the is coming....")
while True:
data = conn.recv(1024)
print(data)
if not data:
print("client is losing。。。。")
break
cmd = os.popen(data.decode()).read()
print("指令:",cmd)#如果是错误的命令,cmd就是“空”,客服端就会一直等...“卡死”
if len(cmd) == 0:
conn.send("the input code is invailded。。。。".encode("utf-8"))
conn.send(str(len(cmd.encode("utf-8"))).encode("utf-8"))#先把指令执行结果,大小发过去
conn.send(cmd.encode("utf-8"))
print("have sending。。。")
server.close()
client:
import socket
client =socket.socket()
client.connect(("localhost",9999))
while True:
msg = input(">>>:").strip()
if len(msg) ==0:continue
client.send(msg.encode("utf-8"))
recv_size = client.recv(1024)#1.接收到文件的“大小”
print(recv_size.decode())
cmd_size = int(recv_size.decode())
recving_size =0#只能放在里面,放外面的话会“卡死”
recving_data = b""#存一个空字节
while recving_size < cmd_size:#文件大小不够,一直接受
data = client.recv(1024)#2.一直接受文件
recving_size += len(data)
recving_data += data
else:
print("have recv done。。。",recving_size,recving_data.decode())
client.close()
conclude:
1."指令"不存在的话,if,别让client一直等
2.汉字的“str”长度 ≠ “bytes”长度
3.recving_size / recving_data ,放在while recv_size < total_ size 外面;
2.黏包:
1.什么是黏包???
conn.send(str(len(cmd.encode("utf-8"))).encode("utf-8"))#先把指令执行结果,大小发过去
conn.send(cmd.encode("utf-8"))#再发送文件执行
像这种,如果你连续send两次,缓存区就会把“它们”当成一条指令;放在缓冲区,发送过去;在client端可能会有size 和 data 连在一起的效果,这种效果就是“黏包”…
server:
conn.send(str(len(cmd.encode("utf-8"))).encode("utf-8"))#先把指令执行结果,大小发过去
client_confrim = conn.recv(1024)#enen。。在这里我等你客服端的“确认”,强行交互,让两次send分开
conn.send(cmd.encode("utf-8"))#再发送文件执行在这里插入代码片
client:
client.send("i am already...".encode("utf-8"))
3.文件操作:
server:
import socket,os
server = socket.socket()
server.bind(("localhost",9999))
server.listen(5)
while True:
conn,addr =server.accept()
print("the is coming....")
while True:
cmd,filename = conn.recv(1024).decode().split()
print(filename)
if os.path.isfile(filename):#如果是一个文件
f = open(filename,"rb")
file_size = os.stat(filename).st_size#获取文件大小
#1.发送total_size
conn.send(str(file_size).encode("utf-8"))
#2.防止黏包
conn.recv(1024)
#3.send data
for line in f:
conn.send(line)
f.close()
server.close()
client:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
client = socket.socket()
client.connect(("localhost",9999))
while True:
msg = input(">>>:").strip()
if len(msg) ==0:continue
if msg.startswith("get"):
client.send(msg.encode("utf-8"))#发送命令
#1.接收total_size
flied_size = client.recv(1024)
print(flied_size)
#2.防止黏包
client.send("i am already....".encode("utf-8"))
filed_size2 = int(flied_size.decode())
received_size = 0
f = open(msg.split()[1]+ "new",'wb')
#3.循环接收size / data
while received_size < filed_size2 :
data = client.recv(1024)#接收数据
received_size += len(data)
f.write(data)
else:
print("file have copy down。。。 ")
f.close()
client.close()
conclude:
server:1.发送total_size(os.stat(fliename).st_size) 2.防止黏包 3.send data
client:1.接收total_size 2.防止黏包 3.循环接收size / data
4.ssh:(导入了md5加密):
server:
import socket,os,hashlib
server = socket.socket()
server.bind(("localhost",9999))
server.listen(5)
while True:
conn,addr =server.accept()
print("the is coming....")
while True:
cmd,filename = conn.recv(1024).decode().split()
print(filename)
if os.path.isfile(filename):#如果是一个文件
f = open(filename,"rb")
file_size = os.stat(filename).st_size#获取文件大小
m = hashlib.md5()
#1.发送total_size
conn.send(str(file_size).encode("utf-8"))
#2.防止黏包
conn.recv(1024)
#3.send data
for line in f:
m.update(line)#md5加密
conn.send(line)
f.close()
conn.send(m.hexdigest().encode("utf-8"))#服务端传过去
server.close()
client:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket,hashlib
client = socket.socket()
client.connect(("localhost",9999))
while True:
msg = input(">>>:").strip()
if len(msg) ==0:continue
if msg.startswith("get"):
client.send(msg.encode("utf-8"))#发送命令
#1.接收total_size
flied_size = client.recv(1024)
print(flied_size)
#2.防止黏包
client.send("i am already....".encode("utf-8"))
filed_size2 = int(flied_size.decode())
received_size = 0
m = hashlib.md5()
f = open(msg.split()[1]+ "new",'wb')
#3.循环接收size / data
while received_size < filed_size2 :
data = client.recv(1024)#接收数据
m.update(data)#客户端循环md5加密
received_size += len(data)
f.write(data)
else:
print("file have copy down。。。 ")
f.close()
print("client_md5",m.hexdigest())#客服端循环接收到的md5
print("server_md5",client.recv(1024))#服务端传过来的md5
client.close()
服务端在最后send md5 ,可能和上面的send date,又发生“黏包”…
deal:
client:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket,hashlib
client = socket.socket()
client.connect(("localhost",9999))
while True:
msg = input(">>>:").strip()
if len(msg) ==0:continue
if msg.startswith("get"):
client.send(msg.encode("utf-8"))#发送命令
#1.接收total_size
flied_size = client.recv(1024)
print(flied_size)
#2.防止黏包
client.send("i am already....".encode("utf-8"))
filed_size2 = int(flied_size.decode())
received_size = 0
m = hashlib.md5()
f = open(msg.split()[1]+ "new",'wb')
#3.循环接收size / data
while received_size < filed_size2 :
#加一个if判断
if filed_size2 - received_size > 1024 :
size =1024
else:#有多少,收多少
size = filed_size2 - received_size
print("the last size:",size)
data = client.recv(size)#接收数据
m.update(data)#客户端循环md5加密
received_size += len(data)
f.write(data)
else:
print("file have copy down。。。 ")
f.close()
print("client_md5",m.hexdigest())#客服端循环接收到的md5
print("server_md5",client.recv(1024))#服务端传过来的md5
client.close()
三、socket.server:
(一种封装,简化了“server”服务端,可以实现多并发)(大概有几类…)
1.class socket.TCPServer(server_address,requesthandlecalss)
2.class socket.UDPServer(server_address,requesthandlecalss)
3.class socket.UnixStreamServer(server_address,requesthandlecalss)
4.class socket.UnixDatagramServer(server_address,requesthandlecalss)
(会有这种继承关系:)
(主要在创建的时候,很简单;大概分这么几步:)
1.创建一个"请求处理类",class requesthandle,这个要继承(socketserver.BaseRequestHandle);而且在他的(def handle)方法里,实现具体的交互内容;
2.实例化一个TCPserver(客户端地址,定义过的请求处理类)
3.server.handle_request()#只处理一次(一般不用);server.server_forever#多次处理
2."服务端"的class封装:
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):#handle里面实现,交互的内容;继承父类的“BaseRequest”,父类里面的handle什么都没写
while True:
try:
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
except ConnectionResetError as e:#socket.server里面的在(client断开时),统一报的这种错误
print("err",e)
break
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
()
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
#实例化一个“服务端”,把地址和requesthandle,传给对象
server.serve_forever()#执行多次
3.实现多用户并发 :(实现多个用户并行交互):
(实例化的时候,socketserver.ThreadingTCPserver(),就这样就行…)
server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
"BaseRequest"的一些方法:
"""
1.fileno()文件描述符
2.serevr_forver(poll_interval = 0.5)
这个请求,会一直执行,直到一个明确的shutdown()请求;在返回shutdown()时,同样也会执行一个service_actions()
poll(检查),以poll_interval = 0.5,0.5s的速度去“扫描”有没有这个shutdown
3.allow_reuse_address
#在client突然断开时,server会一直等到他发送请求(大约30多秒);这条命令可以让server不用去等,重新使用地址
(server.setsockopt(scoket.SOL_SOCKET,socket.so_REUSERADDER,1)...这种在)
"""
这个是“父类”的方法,setup在(_ _ init _ _)、hanlde(try) 和 set up (finally);你可以在请求(先后);加一些你自己的“操作”
四、FTP程序开发:
(client用类作,server用socket.server封装,实现“文件操作”run file、文件上传 put file 和 文件下载 get file )
1.实现一个简单的FTP:
server:
import socketserver,os,json
class MyTCPHandle(socketserver.BaseRequestHandler):
def run(self,*args):
filename =args[0]['filname']
print(filename)#调试
cmd_result = os.popen(filename).read()
print(cmd_result)#调试
self.request.send(str(len(cmd_result.encode("utf-8"))).encode("utf-8"))#1.传大小
self.request.recv(1024)#2.防止黏包
while True:#3.发送数据
self.request.send(cmd_result.encode("utf-8"))
else:
self.request.close()
def get(self,*args):#调试(√)
filename =args[0]['filname']
print(filename)#调试
self.request.send(str(os.stat(filename).st_size).encode("utf-8"))#1.发送文件大小
f = open(filename,'rb')
self.request.recv(1024)#2.防止黏包
for line in f:#3.传送数据
self.request.send(line)
else:
self.request.close()
f.close()
print("写完了...")
def put(self,*args):#调试完成(√)
filename =args[0]['filname']
filesize = args[0]["filsize"]
total_size = filesize#1.接收文件大小
print(total_size)
self.request.send("i am already...".encode("utf-8"))#2.防止黏包
recevied_size = 0
f = open(filename,"wb")
print("打开了")
#3.循环接收date
while recevied_size < int(total_size):
if int(total_size) - recevied_size > 1024:
size = 1024
else:
size = int(total_size) -recevied_size
date3 = self.request.recv(size)
recevied_size +=len(date3)
f.write(date3)
print("正在写....")
else:
print("写完了...")
self.request.close()
f.close()
def handle(self):
while True:
try:
self.date = self.request.recv(1024).strip()
print("{}writen".format(self.client_address[0]))
print(self.date)
cmd_recv = json.loads(self.date.decode())
print(cmd_recv)#调试成功
action = cmd_recv["action"]
print(action)#调试成功
if hasattr(self,action):
func = getattr(self,action)
print("调试")
func(cmd_recv)#把字典传进去
except (OSError,ConnectionError) as e:
print("error",e)
break
if __name__ == "__main__":
HOST,PORT = "localhost",9999
server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandle)
server.serve_forever()
client:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#这里用class类,去实现;
import socket,os,hashlib,json
class FTP(object):
def __init__(self):
self.client = socket.socket()#实例化client
def connect(self,ip,port):
self.client.connect((ip,port))#连接
def help(self,*arges):#测试成功
ways = {
"inter":"交互",
"put_file":"传送文件",
"get_file":"下载文件",
"run_file":"操作文件",}#....通过调用help(key),阅读方法
print(ways[arges[1]])
def intersection(self):#"交互"功能;#输入指令,然后进行处理,传给其他函数...
while True:
msg = input(">>>:").strip()
if len(msg) == 0:continue
code = msg.split()
act = code[0];file = code[1]
if hasattr(self,act):
fuc = getattr(self,act)
fuc(act,file)#把操作和文件名 都 传进去
def put(self,*args):#上传文件,传大小、黏包、发送文件
if os.path.isfile(args[1]):
print("调试")
file_size = os.stat(args[1]).st_size
print("文件大小",file_size)
# self.client.send(file_size.encond("utf-8"))#传送size
# self.client.send(args[1].encond("utf-8"))
#优化一下,用json序列化去传
msg = {
"action":args[0],#传你要干什么
"filname":args[1],#传名字
"filsize":file_size,#传大小
}
self.client.send(json.dumps(msg).encode("utf-8"))
else:print("invailed fliname")
self.client.recv(1024)#防止黏包
f = open(args[1],"rb")
#m = hashlib.md5
for line in f :#send date
self.client.send(line)
#m.update(line);self.client.send(m.hexdigest)
f.close()
self.client.close()
def get(self,*args):#下载文件
msg = {
"action":args[0],#传你要干什么
"filname":args[1],#传文件名字
}
self.client.send(json.dumps(msg).encode("utf-8"))
total_size = self.client.recv(1024).decode()#1.接收大小
self.client.send("i have get size....".encode("utf-8"))#2.黏包
recevied_size = 0
f = open(args[1],'wb')
while recevied_size < int(total_size):
if int(total_size) - recevied_size > 1024:
size = 1024
else:size = int(total_size) - recevied_size
date1 = self.client.recv(size)#接收date
print(date1.decode())#调试
recevied_size += len(date1)
f.write(date1)
else:f.close();self.client.close()
def run(self,*args):#执行文件操作,调试成功(√)
msg = {
"action":args[0],#传你要干什么
"filname":args[1],#传文件名字
}
print(msg)
self.client.send(json.dumps(msg).encode("utf-8"))
total_size = self.client.recv(1024)#1.接收命令大小...
print(total_size)#调试
self.client.send("i am already...".encode("utf-8"))#黏包
recevied_size = 0
recevied_date = b''
#一直接受这个指令...
while recevied_size < int(total_size.decode()):
if int(total_size.decode()) - recevied_size > 1024 :
size = 1024
else:size = int(total_size.decode()) - recevied_size
data2 = self.client.recv(size)#循环收文件
recevied_size += len(data2)#收的字节长度
recevied_date += data2
else:
print(recevied_date.decode())#解码成字符串
self.client.close()
client = FTP()
client.connect("localhost",9999)
client.intersection()
conclude:
1.def handle > while True > try…except…
2.基本的“熟记”
1.os.path.isfile();os.stat(filename).st_size
2.self.client.send(json.dumps(msg).encode(“utf-8”))
步骤多,调试很重要,还有就是这个在“连续操作”的时候,就会有OSError…大佬会的教我一下QAQ