Dayday up ---- python Day8
动态导入模块
# 方法1:
mod = __import__("lib.aa")
print(mod)
instance = getattr(mod.aa,"C")
print(instance)
obj = instance("小花")
print(obj.name)
# 或者:
mod = __import__("lib.aa")
obj = mod.aa.C("小花")
print(obj.name)
# 方法2,官方建议使用
import importlib
aa = importlib.import_module("lib.aa")
print(aa)
print(aa.C("小花").name)
lib.aa
class C(object):
def __init__(self,name):
self.name = name
断言 assert
import importlib
aa = importlib.import_module("lib.aa")
obj = aa.C("小花")
# print(obj.name)
# 断言 assert 和if语句很像
assert type(obj.name) is str # 如果断言错了就不往下走
print(obj.name)
socket
把tcp/ip, udp 封装,暴露的是send, recv
socket families 地址簇
socket.AF_INET ipv4
socket.AF_INET6 ipv6
socket.AF_UNIX localhost
socket types 类型
socket.SOCK_STREAM #for tcp
socket.SOCK_DGRAM #for udp
socket.SOCK_RAW #原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
socket.SOCK_RDM #是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
socket.SOCK_SEQPACKET #废弃了
socket的server 和 client 的基本过程
服务器端:
1、server = socket.socket() 实例化
2、server.bind() 绑定地址和端口
3、server.listen() 监听
4、server.accept()接收消息
5、recv 收取
客户端:
1、client = socket.socket() 实例化
2、client.connect((serverip,port))
3、client.send(data)
4、client.recv(data)
# -*- coding:utf-8 -*- import socket,os server = socket.socket() server.bind(("localhost",9999)) server.listen() while True: conn,addr = server.accept() print("new conn:",addr) while True: print("等待新指令") data = conn.recv(1024) if not data: print("客户端已断开") break print(data) cmd_res = os.popen(data.decode()).read() print("before send:",cmd_res) if len(cmd_res) == 0: cmd_res = "cmd has not output" conn.send( str(len(cmd_res.encode())).encode("utf-8") ) conn.send(cmd_res.encode("utf-8")) print("send done") server.close()
# -*- coding:utf-8 -*- import socket client = socket.socket() client.connect(("localhost",9999)) while True: cmd = input(">>:").strip() if len(cmd) == 0: continue client.send(cmd.encode("utf-8")) cmd_res_size = client.recv(1024) print("命令结果大小:",cmd_res_size) received_size = 0 received_data = b'' while received_size < int(cmd_res_size.decode()): data = client.recv(1024) received_size += len(data) received_data += data else: print("cmd res received done:",received_size ) print(received_data.decode()) client.close()
socket 粘包
造成粘包的原因,两次send会强制将缓冲区的数据 发送给客户端
解决:
1、可以 在一次send之后使用time.sleep(0.5) 但是不支持,慢,卡
2、client_ack = conn.recv(1024) # 等待客户端确认
client_send = conn.send(“等待…”) #发送消息给服务端确认
以上实现了ssh功能,如果我想实现ftp上传下载文件功能怎么实现呢?
ftp server
1、 读取文件名
2、检测文件是否存在
3、打开文件
4、检测文件大小 发给客户端
5、发送文件大小给客户端
6、等待客户端确认
7、开始边读边发
8、发送md5给客户端校验
ftp client
1、判断命令,startswith(“get”)
2、发送命令
3、接收文件大小
4、给服务端发确认消息
5、打开文件
6、边收边写
并且加上 md5功能呢?
回忆hash的使用方法:
import hashlib m = hashlib.md5() m.update(b"test") print(m.hexdigest()) # 结果 098f6bcd4621d373cade4e832627b4f6
ftp_server + md5
# -*- coding:utf-8 -*-
import socket,os,hashlib
server = socket.socket()
server.bind(("localhost",9999))
server.listen()
while True:
conn,addr = server.accept()
print("new connect",addr)
while True:
print("等待新指令...")
data = conn.recv(1024)
if not data:
print("客户端已断开")
break
cmd,filename = data.decode().split()
print(filename)
if os.path.isfile(filename):
f = open(filename,"rb")
m = hashlib.md5()
file_size = os.stat(filename).st_size
conn.send( str(file_size).encode())
conn.recv(1024)
for line in f:
m.update(line)
conn.send(line)
print("file md5", m.hexdigest())
f.close()
conn.send(m.hexdigest().encode())
print("send done")
server.close()
ftp_client + md5
# -*- coding:utf-8 -*-
import socket,hashlib
client = socket.socket()
client.connect(('localhost',9999))
while True:
cmd = input(">>>:").strip()
if len(cmd) == 0: continue
if cmd.startswith("get"):
client.send(cmd.encode())
server_response = client.recv(1024)
print("server response:",server_response)
client.send(b"ready to recv file")
file_total_size = int(server_response.decode())
received_size = 0
filename = cmd.split()[1]
f = open(filename + ".new","wb")
m = hashlib.md5()
while received_size < file_total_size:
if file_total_size - received_size > 1024:
size = 1024
else:
size = file_total_size - received_size
print("last received:",size)
data = client.recv(size)
received_size += len(data)
m.update(data)
f.write(data)
else:
new_file_md5 = m.hexdigest()
print("file recv done", received_size,file_total_size)
f.close()
server_file_md5 = client.recv(1024)
print("server file md5:", server_file_md5)
print("client file md5:",new_file_md5)
client.close()
SocketServer
socketserver 类型
1、socketserver.TCPServer() tcp协议
2、socketserver.UDPServer()
3、socketserver.UnixStreamServer
4、socketserver.UnixDatagramServer
以上类型都是统一继承了 baseserver类
+------------+
| BaseServer |
+------------+
|
v
+-----------+ +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+ +--------------------+
要创建一个socetserver至少要分以下几步:
1、继承baserequesthandle,你必须自己创建一个请求处理类,并且这个类要继承baserequesthandle,并且重写 父亲类里的handle()方法
2、实例化 server classes 比如: tcpserver,传递server ip 和 上面创建的请求处理类给这个server classes,比如 tcpserver
3、server.handle_request() 只处理一个请求 server.serve_forever 处理多个请求 永远执行
4、server_close()
server跟客户端所有的交互都是在handle里面写的
简单的socketserver 实例 :
server:
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler): # 每次请求都会实例化
def handle(self): # 重写handle
while True: # 多次循环
try:
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
self.request.send(self.data.upper())
except ConnectionResetError as e:
print("err",e)
break
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) # 实例化tcpserver,ThreadingTCPServer 多线程多并发
server.serve_forever()
client:
client = socket.socket() #声明socket类型,同时生成socket连接对象
#client.connect(('192.168.16.200',9999))
client.connect(('localhost',9999))
while True:
msg = input(">>:").strip()
if len(msg) == 0:continue
client.send(msg.encode("utf-8"))
data = client.recv(10240)
print("recv:",data.decode())
client.close()
多进程 :
server = socketserver.ForkingTCPServer((HOST, PORT), MyTCPHandler) #在windows上不好使
fileno() 返回文件描述符
server.handle_request() 处理单个请求
server_forever(poll_interval=0.5) 自动调用 service_actions()
allow_reuse_address 地址重用
socket上地址重用
server = socket.socket() #获得socket实例
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

浙公网安备 33010602011771号