python学习第八天
动态导入模块
import os,sys
base =os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base)
'''解释器内部导入方式,只导入module a'''
# mod =__import__("a.test")
# obj =mod.test.m()
# print(mod.test.m().name)
'''官方建议用法,直接导入module a.test'''
import importlib
test =importlib.import_module("a.test")
# print(test.m().name)
断言
'''断言aa的数据类型是字符串,断言正确则执行后面的程序,错误则报错,程序停止'''
assert type("aa") is str
print("ddd")
socket参数
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) 必会
socket.getaddrinfo(host, port, family=0, type=0, proto=0, flags=0) #获取要连接的对端主机地址 必会
sk.bind(address) 必会 s.bind(address) 将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。
sk.listen(backlog) 必会 开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5这个值不能无限大,因为要在内核中维护连接队列
sk.setblocking(bool) 必会 是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。
sk.accept() 必会 接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。接收TCP 客户的连接(阻塞式)等待连接的到来
sk.connect(address) 必会 连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。
sk.connect_ex(address) 同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061
sk.close() 必会 关闭套接字
sk.recv(bufsize[,flag]) 必会 接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。
sk.recvfrom(bufsize[.flag]) 与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。
sk.send(string[,flag]) 必会 将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。
sk.sendall(string[,flag]) 必会 将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。内部通过递归调用send,将所有内容发送出去。
sk.sendto(string[,flag],address) 将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。
sk.settimeout(timeout) 必会 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )
sk.getpeername() 必会 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。
socket实现简易ssh
服务器端
import socket,os
server =socket.socket()
server.bind(("localhost",9999))
server.listen()
while True:
conn,addr =server.accept()
print("新的连接:",addr)
while True:
print("等待新指令")
cmd =conn.recv(1024)
if len(cmd) ==0:
print("客户端断开连接")
break
print("执行指令%s"%cmd)
cmd_res =os.popen(cmd.decode()).read()
res_size =len(cmd_res)
if res_size ==0:
cmd_res ="指令没有执行"
'''发送指令结果长度,方便客户端判断需要接收多少数据'''
conn.send(str(res_size).encode("utf-8"))
'''等待客户端返回确认信息,否则不发送指令执行结果,防止粘包'''
client_ack =conn.recv(1024)
conn.send(cmd_res.encode("utf-8"))
print("指令执行完毕")
server.close()
客户端
import socket
client =socket.socket()
client.connect(("localhost",9999))
while True:
cmd =input(">>>:").strip().encode()
if len(cmd) ==0:continue
client.send(cmd)
'''确认指令结果长度'''
data_size =client.recv(1024)
'''发送确认信息给服务端,以便开始接收指令结果'''
server_ack =client.send(b"ok")
res_size =0
res_data =b''
'''只要接收的数据长度跟之前确认的数据长度不一致就继续接收数据'''
while res_size != int(data_size.decode()):
data =client.recv(1024)
res_size +=len(data)
res_data +=data
else:
print("指令执行结果接收完毕")
print(res_data.decode())
client.close()
socket实现ftp
服务器端
import socket,os,hashlib
server =socket.socket()
server.bind(("localhost",9999))
server.listen()
while True:
conn,addr =server.accept()
print("新的连接:",addr)
while True:
print("等待新指令")
cmd =conn.recv(1024)
if len(cmd) ==0:
print("客户端断开连接")
break
print("执行指令%s"%cmd)
'''获取指令中的文件名'''
filename =os.path.basename(cmd)
'''判断指定的文件是否存在'''
if os.path.isfile(filename):
m =hashlib.md5()
'''获取文件属性中的文件大小'''
file_size =os.stat(filename).st_size
conn.send(str(file_size).encode())
client_ack =conn.recv(1024)
with open(filename,"rb") as f:
for line in f:
'''对文件内容进行md5加密'''
m.update(line)
conn.send(line)
'''输出md5值'''
print(m.hexdigest())
conn.send(m.hexdigest().encode())
else:
print("文件不存在")
print("发送完毕")
server.close()
客户端
import socket,hashlib,os
client =socket.socket()
client.connect(("localhost",9999))
while True:
cmd =input(">>:").strip()
if len(cmd) ==0:continue
filename =os.path.basename(cmd)
'''判断输入的指令是不是以get开头'''
if cmd.startswith("get"):
client.send(cmd.encode("utf-8"))
data_size =client.recv(1024)
client.send(b'ok')
receive_size =0
m =hashlib.md5()
while receive_size !=int(data_size.decode()):
'''判断未接收文件大小,大于1024则设定size为1024,否则size设定为剩余未接收的文件的大小。避免md5与文件内容粘包'''
if int(data_size.decode()) -receive_size >1024:
size =1024
else:
size =int(data_size.decode()) -receive_size
with open(filename +".new","wb") as f:
data =client.recv(size)
receive_size +=len(data)
m.update(data)
f.write(data)
else:
new_filemd5 =m.hexdigest()
print("文件接收完毕")
server_md5 =client.recv(1024)
print("client md5",new_filemd5)
print("server md5",server_md5)
client.close()
socket server模块
import socketserver
'''定义请求处理类,继承BaseRequestHandler,重构它的handle方法'''
class MyTCPHander(socketserver.BaseRequestHandler):
def handle(self):
while True:
try:
self.data =self.request.recv(1024).strip()
if not self.data:
break
print("{}wrote:".format(self.client_address[0]))
print(self.data)
self.request.sendall(self.data.upper())
except ConnectionResetError as e:
print("err",e)
break
if __name__ =="__main__":
HOST,PORT ="localhost",9999
'''实例化一种server类,除了TCPServer还可以定义UDPServer,将监听的IP和端口及请求处理类传入'''
server =socketserver.TCPServer((HOST,PORT),MyTCPHander)
'''调用server对象的serve_forever()方法去处理多个请求'''
server.serve_forever()
创建一个socketserver 至少分以下几步:
- First, you must create a request handler class by subclassing the
BaseRequestHandlerclass and overriding itshandle()method; this method will process incoming requests. 定义一个请求处理类,继承BaseRequestHandler,重构它的handle()方法,handle()处理请求的所有交互 - Second, you must instantiate one of the server classes, passing it the server’s address and the request handler class.实例化一种server类,比如ThreadingTCPServer,将监听的IP和端口以及请求处理类传给它
- Then call the
handle_request()orserve_forever()method of the server object to process one or many requests.调用server对象的serve_forever()方法去处理多个请求 - Finally, call
server_close()to close the socket.调用server_close()关闭服务器程序

浙公网安备 33010602011771号