1.什么是socketserver模塊
socketserver模塊是一個(gè)在TCP協(xié)議讓讓一個(gè)服務(wù)端和多個(gè)客戶端通信的一個(gè)模塊
客戶端代碼
代碼塊
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
msg_s = input('>>>')
sk.send(msg_s.encode('utf-8'))
print(sk.recv(1024).decode('utf-8'))
sk.close()
服務(wù)端代碼
代碼塊
import socketserver #用這個(gè)模塊可以多個(gè)客戶端和一個(gè)服務(wù)端通信
class MySocket(socketserver.BaseRequestHandler):
def handle(self):# 這個(gè)方法的名字是固定的,必須是這個(gè)名字
# 收發(fā)的邏輯代碼
# self.request == conn
msg = self.request.recv(1024).decode('utf-8')
print(msg)
self.request.send(msg.upper().encode('utf-8'))
server = socketserver.TCPServer(('127.0.0.1',8080),MySocket)# 固定的
server.serve_forever()# 開啟一個(gè)永久性的服務(wù)
2.實(shí)現(xiàn)客戶端和服務(wù)端大文件的傳輸
客戶端代碼:
代碼塊
import socket
import os
import json
import struct
sk = socket.socket()
sk.connect(("127.0.0.1",8001))
menu = {"1":"upload","2":"download"}
for k,v in menu.items():
print(k,v)
num = input("請(qǐng)輸入功能選項(xiàng):")
if num == "1":
dic = {"opt":menu.get(num),"filename":None,"filesize":None}
file_path = input("請(qǐng)輸入一個(gè)絕對(duì)路徑:")# 文件的絕對(duì)路徑
# E:\Python S14\day32\實(shí)現(xiàn)大文件的傳輸\11.mp4
filename = os.path.basename(file_path)# 文件名字
filesize = os.path.getsize(file_path)# 獲取用戶輸入的路徑中文件的大小
dic["filename"] = filename
dic["filesize"] = filesize
str_dic = json.dumps(dic) #完成字典的序列化
len_dic = len(str_dic)# 獲取到字典的長(zhǎng)度攒磨,是一個(gè)int類型的數(shù)據(jù) 假如是46或者146灭返,這不重要
b_len_dic = struct.pack('i',len_dic)# 把46或者146統(tǒng)一用一個(gè)4bytes的數(shù)據(jù)表示字典的長(zhǎng)度
sk.send(b_len_dic + str_dic.encode("utf-8"))# 將bytes類型的字典的長(zhǎng)度 + bytes類型的字典的內(nèi)容,一起發(fā)送給服務(wù)器
with open(file_path,"rb") as f:
while filesize:
content = f.read(1024) #將每次傳輸大小最多控制在1024個(gè)字節(jié)
sk.send(content)
filesize -= len(content)
elif num == "2":
pass
服務(wù)端代碼
代碼塊
import socket
import json
import struct
sk = socket.socket()
sk.bind(("127.0.0.1",8001))
sk.listen()
conn,addr = sk.accept()
b_len_dic = conn.recv(4)
len_dic = struct.unpack('i',b_len_dic)[0]# 獲取到字典的真實(shí)實(shí)際長(zhǎng)度
# unpack得到的是一個(gè)元組涵叮,要取下標(biāo)為0的位置
str_dic = conn.recv(len_dic).decode('utf-8') #得到字典
# str_dic = {"opt":menu.get(num),"filename":None,"filesize":None}
dic = json.loads(str_dic) #還原字典
if dic["opt"] == "upload":
filename = "new"+ dic["filename"]
with open(filename,"ab") as f:
while dic['filesize']:
content = conn.recv(1024)
f.write(content)
dic['filesize'] -= len(content)
elif dic["opt"] == "download":
# 客戶端發(fā)來(lái)一個(gè)字典要執(zhí)行的功能惭蹂,以及客戶端自己的絕對(duì)路徑
# 服務(wù)器要返回這個(gè)絕對(duì)路徑中所有文件及文件夾
# 客戶端自己選擇進(jìn)入到哪一層目錄下
# 服務(wù)器都要返回對(duì)應(yīng)目錄下所有文件及文件夾
# 客戶隨時(shí)選擇某一個(gè)目錄下的某一個(gè)文件進(jìn)行下載
# 客戶端發(fā)送來(lái)一個(gè)字典,包含了要進(jìn)行的操作割粮,要下載的文件的絕對(duì)路徑盾碗,
# 根據(jù)絕對(duì)路徑去讀取文件內(nèi)容
# 一邊讀,一遍發(fā)
pass
conn.close()
sk.close()
3.實(shí)現(xiàn)切換目錄的作業(yè)舀瓢,用戶輸入一個(gè)路徑置尔,服務(wù)端返回這個(gè)路徑下所有的文件,如果用戶輸入..氢伟,那么返回上個(gè)目錄層級(jí)榜轿,如果用戶輸入cd,讓用戶輸入要切換的目錄朵锣,服務(wù)器切換到對(duì)應(yīng)的目錄并展示目錄下的文件
客戶端代碼
代碼塊
import socket
import os
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
def func(msg):
sk.send(msg.encode('utf-8')) # 發(fā)送
current_dir = sk.recv(1024).decode('utf-8') #接收
print(current_dir.split('--')) # 獲取接收到當(dāng)前目錄的列表類型數(shù)據(jù)
abs_path = input('請(qǐng)輸入您的根目錄:')
func(abs_path) #執(zhí)行函數(shù)谬盐,發(fā)送和接收
while 1:
cmd = input('請(qǐng)輸入>>>')
# cd + 文件夾 ..
if cmd == '..':
func(cmd)
if cmd == 'cd':
filename = input('請(qǐng)輸入一個(gè)文件夾名:')
func((cmd+' '+filename))
sk.close()
服務(wù)端代碼
代碼塊
import socket
import os
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()
conn,addr = sk.accept()
def send_data(conn,path):
'''你給我一個(gè)目錄,我把目錄發(fā)給client'''
lis_dir = os.listdir(path) #以列表形式獲取當(dāng)前目錄下的東西
str_dir = '--'.join(lis_dir) #將列表拼接成字符串
conn.send(str_dir.encode('utf-8')) #發(fā)送給客戶端
current_dir = conn.recv(1024).decode('utf-8')# 獲取用戶輸入的絕對(duì)路徑
# 以下再處理诚些,都要根據(jù)當(dāng)前路徑去處理飞傀,無(wú)論是返回上一層皇型,還是進(jìn)入下一層
send_data(conn,current_dir)# 把用戶輸入的路徑下的所有文件及文件夾返回給客戶端
#D:/泛娛樂(lè)/騎行/第二季
while 1:
cmd = conn.recv(1024).decode('utf-8')
if cmd == '..':
current_dir = current_dir.split('/')[:-1] #拿到上個(gè)目錄的列表,比如['D:','泛娛樂(lè)','騎行']
current_dir = '/'.join(current_dir) #把上個(gè)目錄的里列表轉(zhuǎn)為字符串砸烦,比如D:/泛娛樂(lè)/騎行
send_data(conn, current_dir)
else:
filename = cmd.split(' ')[1]# 獲取用戶輸入的文件名字
current_dir =current_dir+'/'+filename # 將文件名字添加到當(dāng)前路徑下弃鸦,組成一個(gè)完整的新路徑
if os.path.isdir(current_dir):# 如果客戶輸入的文件名字是一個(gè)文件夾
send_data(conn, current_dir)
else:# 如果不是一個(gè)文件夾
conn.send('您輸入的不是文件夾'.encode('utf-8'))
conn.close()
sk.close()
4.利用hashlib模塊或者h(yuǎn)mac模塊進(jìn)行md5加密計(jì)算身份驗(yàn)證
代碼塊
import hashlib
import hmac #相當(dāng)于hashlib,在hashllib基礎(chǔ)上的封裝幢痘,更簡(jiǎn)單
import os
# print(os.urandom(16),len(os.urandom(16))) #獲取一個(gè)隨即位數(shù)的隨機(jī)數(shù)
sor = b'wusir'
r_str = os.urandom(16)
#用hmac加密
md5_obj = hmac.new(sor,r_str)
r = md5_obj.digest()
print(r)
#用hsahlib加密
md5_obj = hashlib.md5(sor)
md5_obj.update(r_str)
r1 = md5_obj.hexdigest()
5.利用hmac完成登陸驗(yàn)證的例子
客戶端代碼
代碼塊
import socket
import hmac
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
sor = b'alex'
r_str = sk.recv(1024) # 獲得服務(wù)端16位長(zhǎng)度的bytes
md5_obj = hmac.new(sor,r_str)
result = md5_obj.digest()
sk.send(result) #將md5加密后發(fā)給服務(wù)端
msg = sk.recv(1024)
print(msg)
服務(wù)端代碼
代碼塊
import socket
import hashlib
import os
import hmac
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()
conn,addr = sk.accept()
sor = b'alex'
r_str = os.urandom(16)# 隨機(jī)出一個(gè)16位長(zhǎng)度的bytes
conn.send(r_str)
md5_obj = hmac.new(sor,r_str)
result = md5_obj.digest()
msg = conn.recv(1024) #接收客戶端md5加密后的密文
if msg == result:
conn.send(b'success')
else:
conn.send(b'failed')
conn.close()
sk.close()
6.三次登陸
客戶端代碼
代碼塊
import socket
import hashlib
import json
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
dic = {'status':False,'username':None,'password':None}
c = 3 #允許用戶登陸3次
while c:
username = input('請(qǐng)輸入用戶名')
password = input('請(qǐng)輸入密碼')
md5_obj = hashlib.md5(password.encode('utf-8'))
md5_obj.update(username.encode('utf-8'))
pawd_m = md5_obj.hexdigest() #得到一個(gè)加密算法
dic['username'] = username
dic['password'] = pawd_m
str_dic = json.dumps(dic)
sk.send(str_dic.encode('utf-8')) #發(fā)送序列化后的字典
# 服務(wù)器應(yīng)該回復(fù)我一個(gè)這樣的字典:
# 是否登錄成功唬格,如果沒(méi)有登錄成功是因?yàn)槭裁丛颍? res_dic = sk.recv(1024).decode('utf-8')# str_dic
result = json.loads(res_dic)# dic = {status:False/True , username , password, reason}
if result['status']:
print('登錄成功')
break
else:
print('失敗,%s'%result['reason'])
c -= 1
sk.close()
服務(wù)端代碼
代碼塊
import socketserver
import json
import hashlib
class MySocket(socketserver.BaseRequestHandler):
def handle(self):
sor = b'wusir'#
while 1:
str_dic = self.request.recv(1024).decode('utf-8')
# 接收到 一個(gè)字典颜说,類似于{'status':False,'username':None,'password':None}
if not str_dic:break # 當(dāng)客戶端登錄失敗退出程序的情況下购岗,這里會(huì)接收到一個(gè)空消息。
dic = json.loads(str_dic) #還原為原來(lái)字典
if not dic['status']:
'''狀態(tài)是未登陸'''
with open('info','r',encoding='utf-8') as f:
# 文件內(nèi)容的存儲(chǔ)方式 用戶名|密碼
for info in f:
username,pawd_txt = info.strip().split('|')
if username == dic['username']:
'''用戶存在门粪,就對(duì)客戶端發(fā)來(lái)的用戶的加密 密碼再次加密喊积,與文件中對(duì)比'''
md5_obj = hashlib.md5(sor)
md5_obj.update(dic['password'].encode('utf-8'))
pawd = md5_obj.hexdigest()
if pawd_txt == pawd:
'''密碼正確的情況下'''
dic['status'] = True
else:
dic['reason'] = '密碼錯(cuò)誤'
break
else:
'''用戶不存在'''
dic['reason'] = '用戶不存在'
# dic = {status:False , username , password, reason}
# dic = {status:True , username , password}
str_dic = json.dumps(dic)
self.request.send(str_dic.encode('utf-8'))
else:
'''已經(jīng)是登錄成功了'''
server = socketserver.TCPServer(('127.0.0.1',8080),MySocket)
server.serve_forever() #永久開啟服務(wù),不關(guān)閉
文件的內(nèi)容玄妈,文件名:info
alex|d32aa373dec2e4ba7861190083d1da83
xiaoxue|0cb576a05f23a9557278f41329c8dee1
7.對(duì)用戶名和密碼加密后乾吻,發(fā)送到服務(wù)端,服務(wù)端再對(duì)密碼進(jìn)行加密拟蜻,然后與數(shù)據(jù)庫(kù)比對(duì)
代碼塊
import hashlib
sor=b'wusir' #鹽
pwd='123456'
user='alex'
#客戶端對(duì)密碼進(jìn)行第一次加密
md5_obj=hashlib.md5(pwd.encode('utf-8'))
md5_obj.update(user.encode('utf-8'))
res=md5_obj.hexdigest()
#服務(wù)端接收客戶端傳過(guò)來(lái)的密碼溶弟,再利用鹽,進(jìn)行二次加密瞭郑,然后與數(shù)據(jù)庫(kù)比對(duì)辜御。
md5_obj1=hashlib.md5(sor)
md5_obj1.update(res.encode('utf-8'))
res1=md5_obj1.hexdigest()
print(res1) #d32aa373dec2e4ba7861190083d1da83
8. prite()相當(dāng)調(diào)用sys.stdout.write()
代碼塊
import sys
name='hello'
sys.stdout.write(name) #print()就相當(dāng)于調(diào)用底層sys.stdout.write(name)
9. 如何通過(guò)cmd導(dǎo)入python第三方包
pip install 包的名字
例如:pip install Django
別跑,點(diǎn)個(gè)贊再走