python-41-初识hmac与socketserver模块

前言

hmac:用来检验合法性,比如客户端后面发送一些请求,服务端要进行检验是否合法。

基本逻辑:客户端生成一串密文发送给客户端接收,后面客户端发送请求的时候要先校验是否与客户端密文一致

socketserver:是Python标准库中的一个高级模块,能实现多并发服务端。

一、hmac 模块

①服务端:

import socket,os,hmac
sk=socket.socket()
sk.bind(('127.0.0.1',9999))
sk.listen()
conn,addr=sk.accept()

def exp():
    msg=os.urandom(32)              # 随机生成字节
    conn.send(msg)                  # 发送随机生成的字节
    digest=hmac.new(msg).digest()   # 生成密文给下面对比
    res_digest=conn.recv(1024)      # 接收客户端的密文
    res=hmac.compare_digest(digest,res_digest)   # 对比服务端与客户端的密文是否相等,返回bool
    return res
res=exp()
if res:
    print('合法请求')
    sk.close()
else:
    print('不合法请求')
    sk.close()

②客户端:

import socket,hmac
sk=socket.socket()
sk.connect(('127.0.0.1',9999))
msg=sk.recv(1024)
h=hmac.new(msg)
digest=h.digest()
sk.send(digest)
sk.close()

合法与不合法打印结果:

 二、socketserver 模块

①服务端:

import socketserver
class Mysevrer(socketserver.BaseRequestHandler):
    def handle(self):
        while 1:
            msg=self.request.recv(1024).decode('utf-8')
            if msg=='8':break
            print(msg)
            info=input('info send:')
            self.request.send(info.encode('utf-8'))

if __name__ == '__main__':
    server=socketserver.ThreadingTCPServer(('127.0.0.1',9999),Mysevrer)
    server.serve_forever()

②客户端:

import socket
sk=socket.socket()
sk.connect(('127.0.0.1',9999))
while 1:
    msg=input('send:')
    if msg=='8':break
    sk.send(msg.encode('utf-8'))
    ret=sk.recv(1024).decode('utf-8')
    print(ret)
sk.close()

 三、简单实现文件上传功能

基于前一篇:struct模块定制报头ftp实战,注释有解析。

基本逻辑:客户端获取文件大小,处理报头后告诉服务端,服务端每次接收一定字节数。

①服务端,接收:

def sevrer(sk,ip,port,buffer=10240):
    sk.bind((ip, port))
    sk.listen()
    conn,addr=sk.accept()

    head_pack=conn.recv(4)                           # 先接收pack的4个字节
    head_len=struct.unpack('i',head_pack)[0]         # unpack解字节后得到一个元组,取第[0]个即可
    head=conn.recv(head_len).decode('utf-8')         # bytes报头内容
    head_loads=json.loads(head)                      # json报头内容
    FlieSize=head_loads['FlieSize']                  # 取json报头内容中FlieSize对应的值
    with open(head_loads['FlieName'],'wb')as f:      # 创建文件,名称=json报头内容中FlieName对应的名称
        while FlieSize:                              # 如果FlieSize有数值
            if FlieSize>=buffer:                     # 大于等于buffer,给下面直接写入buffer个字节
                f.write(conn.recv(buffer))           # 写入buffer个字节
                FlieSize-=buffer                     # FlieSize每次减少buffer个字节
            else:                                    # 如果小于buffer个字节,直接读完
                f.write(conn.recv(buffer))           # 读取完毕,退出循环
                break
    conn.close()
    sk.close()                                       # 结束,关闭连接

if __name__ == '__main__':
    import socket, struct, json
    sk = socket.socket()
    sevrer(sk,ip='127.0.0.1',port=8888)

②客户端,上传:

def client(sk,FlieName,FliePath,buffer=10240):

    head={
        'FlieName': FlieName,                                     # 文件名
        'FliePath': FliePath,                                     # 文件目录
        'FlieSize': None,}                                        # 文件大小为空
    cur_path=os.path.join(head['FliePath'],head['FlieName'])      # 拼接文件路径
    FlieSize=os.path.getsize(cur_path)                            # 获取文件字节大小
    head['FlieSize']=FlieSize                                     # 将文件大小传入head字典
    head_bytes=json.dumps(head).encode('utf-8')                   # 序列化
    head_len=len(head_bytes)                                      # 报头的长度
    head_pack=struct.pack('i',head_len)                           # pack为4个字节长度
    sk.send(head_pack)                                            # 发送pack的4个字节
    sk.send(head_bytes)                                           # 发送bytes类型报头
    with open(cur_path,'rb')as f:                                 # 打开拼接路径的文件
        while FlieSize:                                           # 如果FlieSize有数值
            if FlieSize>=buffer:                                  # 大于等于buffer,给下面直接写入buffer个字节
                sk.send(f.read(buffer))                           # 写入buffer个字节
                FlieSize-=buffer                                  # FlieSize每次减少buffer个字节
            else:
                sk.send(f.read(buffer))                           # 如果小于buffer个字节,直接读完
                break                                             # 读取完毕,退出循环
    sk.close()                                                    # 关闭连接
    return FlieSize

if __name__ == '__main__':
    import socket, struct, os, json
    sk = socket.socket()
    sk.connect(('127.0.0.1',8888))

    FlieName=r'bash教程.pdf'
    FliePath=r'C:\Users\Administrator\Desktop'
    print('上传成功,总共字节:',client(sk,FlieName,FliePath))

 欢迎来大家QQ交流群一起学习:482713805

posted @ 2020-03-26 20:53  广深-小龙  阅读(192)  评论(0编辑  收藏  举报