python_登陆验证文件上传下载_socket

client.py
import os
import sys
import json
import struct
import socket

# 下载--接收文件
def download(sk):  # 下载
    opt_dic = {'operate':'download'}
    my_send(sk,opt_dic)
    msg = my_recv(sk)
    with open(msg['filename'], 'wb') as f:
        print('File is downloading...')
        while msg['filesize'] > 0:
            content = sk.recv(1024)
            msg['filesize'] -= len(content)
            f.write(content)
        print('File download finished...')

# 上传--传送文件
def upload(sk):
    opt_dic = {'operate':'upload'}
    my_send(sk,opt_dic)
    path_list=my_recv(sk)['upload_path']
    for index, path in enumerate(path_list,1):
        print(index, path)
    selected_path = input('请输入目的文件夹的序号:')
    uploaded_file = input('请输入本地要上传的文件的全路径:')
    filename = os.path.basename(uploaded_file)
    filesize = os.path.getsize(uploaded_file)
    dic = {'uploaded_path': selected_path, 'filename': filename, 'filesize': filesize}
    my_send(sk,dic)

    with open(uploaded_file, mode='rb') as f:
        print('File is uploading...')
        while filesize > 0:
            content = f.read(1024)
            filesize -= len(content)
            sk.send(content)
        print('File upload finished')


# 登录
def login(sk):
    while True:
        usr = input('用户名:').strip()
        pwd = input('密 码 :').strip()
        dic = {'username': usr, 'password': pwd}  # 将用户名和密码放在字典里发过去,而不是单独发送。
        my_send(sk, dic)
        ret = my_recv(sk)
        if ret['operate'] == 'login' and ret['result']:
            print('登录成功')
            break
        else:
            print('登录失败')

# 将 sk.recv(num)封装到函数里:
# 1-提高复用度;2-每次都使用 struct防止粘包 3;将 server,client实现某一功能的代码对应起来(如,两边都有 download())
def my_recv(sk):     # 接收
    msg_len = sk.recv(4)
    dic_len = struct.unpack('i', msg_len)[0]
    msg = sk.recv(dic_len).decode('utf-8')
    msg = json.loads(msg)
    return msg

# 将 sk.send(msg)封装到函数里:
# 1-提高复用度;2-每次都使用 struct防止粘包 3;将 server,client实现某一功能的代码对应起来(如,两边都有 download())
def my_send(sk,dic):   # 发送 {'username': usr, 'password': pwd} 或者 {'operate':'download'}
    str_dic = json.dumps(dic)   # 网络通信中 一般使用 json而非 pickle
    b_dic = str_dic.encode('utf-8')  # 将 json字符串 encode成 字节串
    mlen = struct.pack('i', len(b_dic))
    sk.send(mlen)  # 4个字节 表示字典转成字节之后的长度
    sk.send(b_dic)  # 具体的字典数据

def exit(sk):
    # sys.exit()
    global flag
    flag = False
    opt_dic = {'operate': 'exit'}
    my_send(sk,opt_dic)
    # sk.close()


if __name__ == '__main__':

    sk = socket.socket()
    # sk.connect(('192.168.14.109',9012))
    sk.connect(('127.0.0.1',9001))

    login(sk)   # 登录
    # 上传下载
    flag=True
    while flag:
        opt_lst = ['upload','download','exit']
        for index,opt in enumerate(opt_lst,1):
            print(index,opt)
        num = int(input('请选择您要操作的序号 :'))
        getattr(sys.modules[__name__],opt_lst[num-1])(sk)
    sk.close()
    # sk.close()

server.py (socket版)
import os
import sys
import json
import struct
import socket
import hashlib

# 将 conn.send(msg)封装到函数里,1-提高复用度;2-每次都使用 struct防止粘包
def my_send(conn,dic):
    str_dic = json.dumps(dic)
    b_dic = str_dic.encode('utf-8')
    mlen = struct.pack('i', len(b_dic))
    conn.send(mlen)  # 4个字节 表示字典转成字节之后的长度
    conn.send(b_dic)  # 具体的字典数据

# download--发送文件
def download(conn):
    abs_path = r'C:Users12078PycharmProjectsOldBoyDay32登陆验证文件下载_完整版视频文件源位置测试视频.mp4'
    filename = os.path.basename(abs_path)
    filesize = os.path.getsize(abs_path)
    dic = {'filename': filename, 'filesize': filesize}
    my_send(conn,dic)

    with open(abs_path, mode='rb') as f:
        while filesize > 0:
            content = f.read(1024)
            filesize -= len(content)
            conn.send(content)

def upload(conn):
    upload_path = ['upload_path1', 'upload_path2']
    my_send(conn,{'upload_path':upload_path})
    file_dic=my_recv(conn)
    file_path = upload_path[int(file_dic['uploaded_path']) - 1] + '\' + file_dic['filename']
    with open(file_path, 'wb') as f:
        while file_dic['filesize'] > 0:
            content = conn.recv(1024)
            file_dic['filesize'] -= len(content)
            f.write(content)


# 将 conn.recv(num)封装到函数里,1-提高复用度;2-每次都使用 struct防止粘包
def my_recv(conn):
    msg_len = conn.recv(4)
    dic_len = struct.unpack('i', msg_len)[0]
    msg = conn.recv(dic_len).decode('utf-8')
    msg = json.loads(msg)  # 网网络通信中使用较多的是json而不是pickle
    return msg

# 将密码进行加密,使用username作为 salt
def get_md5(username,password):
    md5 = hashlib.md5(username.encode('utf-8'))
    md5.update(password.encode('utf-8'))
    return md5.hexdigest()

# 登录
def login(conn):
    flag = True
    while flag:
        msg = my_recv(conn)  # 接收到的是 dic = {'username': usr, 'password': pwd}
        with open('userinfo') as f:
            for line in f:
                name, pwd = line.strip().split('|')
                if name == msg['username'] and pwd == get_md5(name, msg['password']):
                    res, flag = True, False
                    break
            else:
                res = False
            dic = {'operate': 'login', 'result': res}
            my_send(conn, dic)  # 将登录结果发送给 client

def exit(conn):
    # sys.exit()
    # sk.close()
    global flag
    flag = False
    conn.close()  # 只断开和客户端的连接,不关闭服务。



if __name__ == '__main__':


    sk = socket.socket()
    sk.bind(('127.0.0.1',9001))
    sk.listen()

    while True:  # 允许和多个客户端连接(非并行)
        conn,_ =sk.accept()
        # 有了一个客户端来连接你
        login(conn)

        flag = True
        while flag:
            # 接收消息,根据用户的选择进行上传/下载操作
            opt_dic = my_recv(conn)  # {'operate':'download'} 或 {'operate':'upload'}
            if hasattr(sys.modules[__name__],opt_dic['operate']):
                getattr(sys.modules[__name__],opt_dic['operate'])(conn)

        # conn.close()
    sk.close()

server.py(socketserver版)
import os
import sys
import json
import struct
import hashlib
import socketserver

class Myserver(socketserver.BaseRequestHandler):
    def handle(self):
        conn = self.request
        login(conn)
        flag = True
        while flag:  # 不需要更外层的那个 while了,和多个客户端通讯的任务交给了socketserver.
            try:
                # 接收消息,根据用户的选择进行上传/下载操作
                opt_dic = my_recv(conn)  # {'operate':'download'} 或 {'operate':'upload'} ,{'operate':'exit'}
                if hasattr(sys.modules[__name__], opt_dic['operate']):
                    getattr(sys.modules[__name__], opt_dic['operate'])(conn)
                    if opt_dic['operate']=='exit': flag=False  # 这样做判断,虽然破坏了 反射的简介,但【只有这样】才能退出连接。
            except ConnectionResetError:  # 处理异常断开连接,比如客户端非正常退出。
                break
        conn.close()  # 只断开和客户端的连接,不关闭服务。


# 将 conn.send(msg)封装到函数里,1-提高复用度;2-每次都使用 struct防止粘包; 3-每次 send/recv都struct一下。
def my_send(conn,dic):
    str_dic = json.dumps(dic)
    b_dic = str_dic.encode('utf-8')
    mlen = struct.pack('i', len(b_dic))
    conn.send(mlen)  # 4个字节 表示字典转成字节之后的长度
    conn.send(b_dic)  # 具体的字典数据

# download--发送文件
def download(conn):
    abs_path = r'C:Users12078PycharmProjectsOldBoyDay32登陆验证文件下载_完整版视频文件源位置测试视频.mp4'
    filename = os.path.basename(abs_path)
    filesize = os.path.getsize(abs_path)
    dic = {'filename': filename, 'filesize': filesize}
    my_send(conn,dic)

    with open(abs_path, mode='rb') as f:
        while filesize > 0:
            content = f.read(1024)
            filesize -= len(content)
            conn.send(content)

def upload(conn):
    upload_path = ['upload_path1', 'upload_path2']
    my_send(conn,{'upload_path':upload_path})
    file_dic=my_recv(conn)
    file_path = upload_path[int(file_dic['uploaded_path']) - 1] + '\' + file_dic['filename']
    with open(file_path, 'wb') as f:
        while file_dic['filesize'] > 0:
            content = conn.recv(1024)
            file_dic['filesize'] -= len(content)
            f.write(content)


# 将 conn.recv(num)封装到函数里,1-提高复用度;2-每次都使用 struct防止粘包; 3-每次 send/recv都struct一下。
def my_recv(conn):
    msg_len = conn.recv(4)
    dic_len = struct.unpack('i', msg_len)[0]
    msg = conn.recv(dic_len).decode('utf-8')
    msg = json.loads(msg)  # 网网络通信中使用较多的是json而不是pickle
    return msg

# 将密码进行加密,使用username作为 salt
def get_md5(username,password):
    md5 = hashlib.md5(username.encode('utf-8'))
    md5.update(password.encode('utf-8'))
    return md5.hexdigest()

# 登录
def login(conn):
    flag = True
    while flag:
        msg = my_recv(conn)  # 接收到的是 dic = {'username': usr, 'password': pwd}
        with open('userinfo') as f:
            for line in f:
                name, pwd = line.strip().split('|')
                if name == msg['username'] and pwd == get_md5(name, msg['password']):
                    res, flag = True, False
                    break
            else:
                res = False
            dic = {'operate': 'login', 'result': res}
            my_send(conn, dic)  # 将登录结果发送给 client


def exit(conn):
    # sys.exit()
    # sk.close()
    # global flag
    # flag  = False
    conn.close()  # 只断开和客户端的连接,不关闭服务。



if __name__ == '__main__':
    flag = True
    server = socketserver.ThreadingTCPServer(('127.0.0.1', 9001), Myserver)
    server.serve_forever()

原文地址:https://www.cnblogs.com/Collin-pxy/p/13034187.html