day 29 socketserver ftp功能的简单讲解
1.上传下载的简单示例
server:
import socket
import struct
import json
server =socket.socket()
server.bind(('127.0.0.1',8001))
server.listen()
conn,addr = server.accept()
#首先接收文件的描述信息的长度
struct_data_len = conn.recv(4)
data_len = struct.unpack('i',struct_data_len)[0]
#通过文件信息的长度将文件的描述信息全部接收
print('data_len>>>>',data_len)
file_info_bytes =conn.recv(data_len)
# 将文件描述信息转换为字典类型,以便操作
file_info_json = file_info_bytes.decode('utf-8')
file_info_dict = json.loads(file_info_json) ##{'file_name': 'aaa.mp4', 'file_size': 24409470}
print(file_info_dict)
#统计每次接收的累计长度
recv_sum =0
flie_path= 'D:\s18\jj' +'\\' + file_info_dict['file_name']
with open(flie_path, 'wb') as f:
while recv_sum < file_info_dict['fil_size']:
every_recv_data = conn.recv(1024)
recv_sum += len(every_recv_data)
f.write(every_recv_data)
client:
import os
import socket
import json
import struct
client = socket.socket()
client.connect(('127.0.0.1',8001))
#统计文件大小
file_size = os.path.getsize(r'D:\python_workspace_s18\day029\aaa.mp4')
# 统计文件描述信息,给服务端,服务端按照我的文件描述信息来保存文件,命名文件等等,现在放点一个字典里面了
file_info ={
'file_name':'aaa.mp4',
'file_size':file_size
}
#由于字典无法直接为转换成bytes类型的数据,所以需要json来讲字典转换成json字符串,在把字符串转换成字节类型的数据进行发送
#json.dumps是将字典转转换为json字符串的方法
file_info_json = json.dumps(file_info)
#将字符串转换成bytes类型的数据
file_info_byte = file_info_json.encode('utf-8')
#为了防止黏包现象,将文件描述信息的长度打包后和文件的描述信息的数据一起发送过去
data_len = len(file_info_byte)
data_len_struct = struct.pack('i',data_len)
#发送文件描述信息
client.send(data_len_struct+file_info_byte)
#定义一个变量,=0,作为每次读取文件的长度的累计值
sum = 0
#打开的aaa.mp4文件,rb的形式
with open('aaa.mp4','rb') as f:
#循环读取文件内容
while sum < file_size:
#每次读取的文件内容,每次读取1024B大小的数据
every_read_data = f.read(1024)
#将每次读取的文件的真实数据反送给服务器
sum +=len(every_read_data)
client.send(every_read_data)
2.socketserver模块实现并发
用socketserver可以实现和多个客户端通信,它是在socket的基础上进行了一层封装,也就是说底层还是调用的socket.
实例:
server端:
import socketserver
# 自己写一个类,类名自己随便定义,然后继承socketserver这个模块里面的类BaseRequestHandler
class Myserver(socketserver.BaseRequestHandler):
#写一个handle方法,必须叫这个名字
def handle(self):
#self.request #self.request相当于一个conn
while 1:
from_client_msg = self.request.recv(1024) #self.request = conn
print(from_client_msg.decode('utf-8'))
msg = input('服务端说:')
self.request.send(msg.encode('utf-8')) #发消息
#拿到了我们队每个客户端的通道,那么我们自己在这个方法里面就写我们接收消息和发送消息的逻辑就可以了
if __name__ == '__main__':
ip_port = ('127.0.0.1',8001)
#设置 allow_reuse_adress允许服务器重用地址
socketserver.TCPServer.allow_reuse_adress = True
#thread线程
#使用socketserver的ThreadingTCPServer这个类,将ip和端口的元组传进去,还需要将上面咱么定义的类传进去,得到一个对象相当于我们通过它进行了bind,listen
server = socketserver.ThreadingTCPServer(ip_port,Myserver)
#使用我们上面这个类型的对象来执行server_foever()这个方法,服务会一直开启,就先京东网站一样,不能关闭网站,server_foever()帮我们进行了accept
server.serve_forever()
client端:
import socket
# 创建一个socket链接,SOCK_STREAM代表使用TCP协议
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#连接到客户端
client.connect(('127.0.0.1',8001))
while 1:
msg = input('客户端说:')
client.send(msg.encode('uft-8'))
from_server_msg = client.recv(1024)
print(from_server_msg.decode('utf-8'))
3.验证客户端的连接合法性
首先介绍两种方法:
1.os.urandom(n)
其中os.urandom(n)是一种bytes类型的随机生成n个字节字符串的方法,而且每次生成的值都不相同。再加上md5等加密的处理。就能够形成不同长度相同的字符串了。
os.urandom(n)函数在python官方文档中做出了这样的解释
函数定位:Return a string of n random bytessuitable for cryptographic use.
意思就是,返回一个有n个bytes那么长的string,然后很适合加密。
然后在这个函数中,在文档中,被归结于os这个库的Miscellaneous Functions,意思是不同种类的函数(也可以说是混种函数)
原因是:This function returns random bytes from an OS-specific randomness source
(函数返回的随机字节是根据不同的操作系统特定的随机函数资源。即,这个函数是调用OS内部自带的随机函数,有特异性)
使用的方法:
import os
from hashlib import md5
for i in range(10):
print (md5(os.urandom(24)).hexdigest())
2.hamc:我们完全可以用hashlib来实现,python自带的hmac模块实现了标准的Hmac算法,首先需要准备待计算的原始消息message,随机key,哈希算法,这里采用MD5,使用hmac的代码如下:
可见的使用hmac和普通hash算法非常类似,hmac输出的长度和原始哈希算法的长度一致。需要注意的是传入的key和message都是bytes类型,str类型需要首先编码bytes。
import hmac
import random
message = b'Hello world'
key = b'secret'
h = hmac.new(key,message,digestmod='MD5')
print(h.hexdigest())
# 比较两个密文是否相同,可以用hmac.compara_digest(密文,密文),会返回True或者False。def hmac_md5(key,s):
return hmac.new(key.encode('utf-8'),s.encode('utf-8'),'MD5').hexdigest()
class User(object):
def __init__(self,username,password):
self.username = username
self.key = ''.join([chr(random.randint(48,122)) for i in range(20)])
self.password = hmac_md5(self.key,password)
验证客户端合法性连接实例
server端:
from socket import *
import hmac,os
secret_key =b'Jedan has a big key!'
def conn_auth(conn):
"""
验证客户端到服务器的连接
:param conn:
:return:
"""
msg= conn.recv(32)
h = hmac.new(secret_key,msg)
digest = h.digest()
conn.sendall(digest)
def client_handler(ip_port,bufsize=1024):
tcp_socket_client = socket(AF_INET,SOCK_STREAM)
tcp_socket_client.connect(ip_port)
conn_auth(tcp_socket_client)
while True:
data= input('>>:').strip()
if not data:continue
if data == 'quit':break
tcp_socket_client.sendall(data.encode('utf-8'))
respone =tcp_socket_client.recv(bufsize)
print(respone.decode('utf-8'))
tcp_socket_client.close()
if __name__ == '__main__':
ip_port = ('127.0.0.1',9999)
bufsize = 1024
client_handler(ip_port,bufsize)
client端:
from socket import *
import hmac,os
secret_key =b'Jedan has a big key!'
def conn_auth(conn):
"""
验证客户端到服务器的连接
:param conn:
:return:
"""
msg= conn.recv(32)
h = hmac.new(secret_key,msg)
digest = h.digest()
conn.sendall(digest)
def client_handler(ip_port,bufsize=1024):
tcp_socket_client = socket(AF_INET,SOCK_STREAM)
tcp_socket_client.connect(ip_port)
conn_auth(tcp_socket_client)
while True:
data= input('>>:').strip()
if not data:continue
if data == 'quit':break
tcp_socket_client.sendall(data.encode('utf-8'))
respone =tcp_socket_client.recv(bufsize)
print(respone.decode('utf-8'))
tcp_socket_client.close()
if __name__ == '__main__':
ip_port = ('127.0.0.1',9999)
bufsize = 1024
client_handler(ip_port,bufsize)
1.上传下载的简单示例
server:
import socket
import struct
import json
server =socket.socket()
server.bind(('127.0.0.1',8001))
server.listen()
conn,addr = server.accept()
#首先接收文件的描述信息的长度
struct_data_len = conn.recv(4)
data_len = struct.unpack('i',struct_data_len)[0]
#通过文件信息的长度将文件的描述信息全部接收
print('data_len>>>>',data_len)
file_info_bytes =conn.recv(data_len)
# 将文件描述信息转换为字典类型,以便操作
file_info_json = file_info_bytes.decode('utf-8')
file_info_dict = json.loads(file_info_json) ##{'file_name': 'aaa.mp4', 'file_size': 24409470}
print(file_info_dict)
#统计每次接收的累计长度
recv_sum =0
flie_path= 'D:\s18\jj' +'\\' + file_info_dict['file_name']
with open(flie_path, 'wb') as f:
while recv_sum < file_info_dict['fil_size']:
every_recv_data = conn.recv(1024)
recv_sum += len(every_recv_data)
f.write(every_recv_data)
client:
import os
import socket
import json
import struct
client = socket.socket()
client.connect(('127.0.0.1',8001))
#统计文件大小
file_size = os.path.getsize(r'D:\python_workspace_s18\day029\aaa.mp4')
# 统计文件描述信息,给服务端,服务端按照我的文件描述信息来保存文件,命名文件等等,现在放点一个字典里面了
file_info ={
'file_name':'aaa.mp4',
'file_size':file_size
}
#由于字典无法直接为转换成bytes类型的数据,所以需要json来讲字典转换成json字符串,在把字符串转换成字节类型的数据进行发送
#json.dumps是将字典转转换为json字符串的方法
file_info_json = json.dumps(file_info)
#将字符串转换成bytes类型的数据
file_info_byte = file_info_json.encode('utf-8')
#为了防止黏包现象,将文件描述信息的长度打包后和文件的描述信息的数据一起发送过去
data_len = len(file_info_byte)
data_len_struct = struct.pack('i',data_len)
#发送文件描述信息
client.send(data_len_struct+file_info_byte)
#定义一个变量,=0,作为每次读取文件的长度的累计值
sum = 0
#打开的aaa.mp4文件,rb的形式
with open('aaa.mp4','rb') as f:
#循环读取文件内容
while sum < file_size:
#每次读取的文件内容,每次读取1024B大小的数据
every_read_data = f.read(1024)
#将每次读取的文件的真实数据反送给服务器
sum +=len(every_read_data)
client.send(every_read_data)
2.socketserver模块实现并发
用socketserver可以实现和多个客户端通信,它是在socket的基础上进行了一层封装,也就是说底层还是调用的socket.
实例:
server端:
import socketserver
# 自己写一个类,类名自己随便定义,然后继承socketserver这个模块里面的类BaseRequestHandler
class Myserver(socketserver.BaseRequestHandler):
#写一个handle方法,必须叫这个名字
def handle(self):
#self.request #self.request相当于一个conn
while 1:
from_client_msg = self.request.recv(1024) #self.request = conn
print(from_client_msg.decode('utf-8'))
msg = input('服务端说:')
self.request.send(msg.encode('utf-8')) #发消息
#拿到了我们队每个客户端的通道,那么我们自己在这个方法里面就写我们接收消息和发送消息的逻辑就可以了
if __name__ == '__main__':
ip_port = ('127.0.0.1',8001)
#设置 allow_reuse_adress允许服务器重用地址
socketserver.TCPServer.allow_reuse_adress = True
#thread线程
#使用socketserver的ThreadingTCPServer这个类,将ip和端口的元组传进去,还需要将上面咱么定义的类传进去,得到一个对象相当于我们通过它进行了bind,listen
server = socketserver.ThreadingTCPServer(ip_port,Myserver)
#使用我们上面这个类型的对象来执行server_foever()这个方法,服务会一直开启,就先京东网站一样,不能关闭网站,server_foever()帮我们进行了accept
server.serve_forever()
client端:
import socket
# 创建一个socket链接,SOCK_STREAM代表使用TCP协议
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#连接到客户端
client.connect(('127.0.0.1',8001))
while 1:
msg = input('客户端说:')
client.send(msg.encode('uft-8'))
from_server_msg = client.recv(1024)
print(from_server_msg.decode('utf-8'))
3.验证客户端的连接合法性
首先介绍两种方法:
1.os.urandom(n)
其中os.urandom(n)是一种bytes类型的随机生成n个字节字符串的方法,而且每次生成的值都不相同。再加上md5等加密的处理。就能够形成不同长度相同的字符串了。
os.urandom(n)函数在python官方文档中做出了这样的解释
函数定位:Return a string of n random bytessuitable for cryptographic use.
意思就是,返回一个有n个bytes那么长的string,然后很适合加密。
然后在这个函数中,在文档中,被归结于os这个库的Miscellaneous Functions,意思是不同种类的函数(也可以说是混种函数)
原因是:This function returns random bytes from an OS-specific randomness source
(函数返回的随机字节是根据不同的操作系统特定的随机函数资源。即,这个函数是调用OS内部自带的随机函数,有特异性)
使用的方法:
import os
from hashlib import md5
for i in range(10):
print (md5(os.urandom(24)).hexdigest())
2.hamc:我们完全可以用hashlib来实现,python自带的hmac模块实现了标准的Hmac算法,首先需要准备待计算的原始消息message,随机key,哈希算法,这里采用MD5,使用hmac的代码如下:
可见的使用hmac和普通hash算法非常类似,hmac输出的长度和原始哈希算法的长度一致。需要注意的是传入的key和message都是bytes类型,str类型需要首先编码bytes。
import hmac
import random
message = b'Hello world'
key = b'secret'
h = hmac.new(key,message,digestmod='MD5')
print(h.hexdigest())
# 比较两个密文是否相同,可以用hmac.compara_digest(密文,密文),会返回True或者False。def hmac_md5(key,s):
return hmac.new(key.encode('utf-8'),s.encode('utf-8'),'MD5').hexdigest()
class User(object):
def __init__(self,username,password):
self.username = username
self.key = ''.join([chr(random.randint(48,122)) for i in range(20)])
self.password = hmac_md5(self.key,password)
验证客户端合法性连接实例
server端:
from socket import *
import hmac,os
secret_key =b'Jedan has a big key!'
def conn_auth(conn):
"""
验证客户端到服务器的连接
:param conn:
:return:
"""
msg= conn.recv(32)
h = hmac.new(secret_key,msg)
digest = h.digest()
conn.sendall(digest)
def client_handler(ip_port,bufsize=1024):
tcp_socket_client = socket(AF_INET,SOCK_STREAM)
tcp_socket_client.connect(ip_port)
conn_auth(tcp_socket_client)
while True:
data= input('>>:').strip()
if not data:continue
if data == 'quit':break
tcp_socket_client.sendall(data.encode('utf-8'))
respone =tcp_socket_client.recv(bufsize)
print(respone.decode('utf-8'))
tcp_socket_client.close()
if __name__ == '__main__':
ip_port = ('127.0.0.1',9999)
bufsize = 1024
client_handler(ip_port,bufsize)
client端:
from socket import *
import hmac,os
secret_key =b'Jedan has a big key!'
def conn_auth(conn):
"""
验证客户端到服务器的连接
:param conn:
:return:
"""
msg= conn.recv(32)
h = hmac.new(secret_key,msg)
digest = h.digest()
conn.sendall(digest)
def client_handler(ip_port,bufsize=1024):
tcp_socket_client = socket(AF_INET,SOCK_STREAM)
tcp_socket_client.connect(ip_port)
conn_auth(tcp_socket_client)
while True:
data= input('>>:').strip()
if not data:continue
if data == 'quit':break
tcp_socket_client.sendall(data.encode('utf-8'))
respone =tcp_socket_client.recv(bufsize)
print(respone.decode('utf-8'))
tcp_socket_client.close()
if __name__ == '__main__':
ip_port = ('127.0.0.1',9999)
bufsize = 1024
client_handler(ip_port,bufsize)