1-基于socket实现的登录注册

需求

讲解视频参考:https://www.bilibili.com/video/BV1pa411r7TE?p=7&vd_source=f56f96c7f7894594fdc04129b7d97ff6

-- 基于socket和面向对象,实现一个注册功能,密码尽量以密文形式传输和存储
    - 文件构成
        D:\demo
            - server.py
            - client.py
            - user.txt   # 你也可以选择其他类型的文件
    - 需求:
        - 客户端和服务端都要使用面向对象实现,但不考虑多用户同时登录的问题(无需考虑io多路复用,和多线程实现多用户)
        - 客户端运行程序后,有登录和注册、退出三个功能
        - 当用户选择注册,让用户输入用户名和密码,并在客户端对密码进行md5加密,然后将数据传给 sever 端,server 校验用户名是否存在
            - 存在则返回用户已存在,让客户端重新注册
            - 如果不存在,则保存注册信息,并返回注册成功
        - 如果用户选择登录,将用户输入的信息发送到server端进行校验
            - 成功提示登录成功
            - 否则提示登录失败
        - 可选升级:如果用户已经登录成功,再次选择登录功能后,直接提示"自动登录成功",而无需再次输入用户名和密码
        - 可选升级:如果用户选择退出,结束客户端程序并断开连接,然后server端断开与当前客户端的连接
        	- 客户端正常断开,向server端发一个断开的消息
        	- 客户端异常断开,server端也要进行断开处理

基础版

client.py

import hashlib
import socket
import json


class Client(object):
    login_status = False

    def __init__(self, ip, port):
        self.ip = ip
        self.port = port
        self.sock = socket.socket()
        self.sock.connect(('127.0.0.1', 8887), )

    def md5(self, pwd):
        """ 专门对密码进行加密,并返回加密后的密码 """
        return hashlib.md5(pwd.encode()).hexdigest()

    def register(self):
        """ 专门负责注册逻辑的方法 """
        while True:
            user = input('user: ').strip()
            pwd = input('pwd: ').strip()
            if not user or not pwd:
                continue
            md_pwd = self.md5(pwd)
            data = {"user": user, "pwd": md_pwd, "action_type": "register"}
            self.sock.send(json.dumps(data).encode())
            msg_data = self.sock.recv(1024).decode()
            msg_data = json.loads(msg_data)
            if msg_data['code'] == 201:  # 用户已存在
                print(msg_data['code_content'])
            else:  # 注册成功
                print(msg_data['code_content'])
                break

    def login(self):
        """ 专门负责登录逻辑的方法 """
        if self.login_status:
            print('已为你自动登录....')
            return
        while True:
            user = input('user: ').strip()
            pwd = input('pwd: ').strip()
            if not user or not pwd:
                continue
            md_pwd = self.md5(pwd)
            data = {"user": user, "pwd": md_pwd, "action_type": "login"}
            self.sock.send(json.dumps(data).encode())
            msg_data = self.sock.recv(1024).decode()
            msg_data = json.loads(msg_data)
            if msg_data['code'] == 301:  # 用户名或者密码错误
                print(msg_data['code_content'])
                self.login_status = False
            else:  # 登录成功
                print(msg_data['code_content'])
                self.login_status = True
                break

    def q(self):
        """ 退出程序 """
        exit('你选择退出')

    def logout(self):
        """ 退出登录状态 """
        if self.login_status:
            self.login_status = False
            print(f'当前用户已退出.....')
        else:
            print('用户没有登录')

    def handler(self):
        """
        专门用于跟客户端转发消息的方法
        :return:
        """
        tmp_dict = {
            "1": ['登录', self.login],
            "2": ['注册', self.register],
            "3": ['退出', self.q],
            "4": ['退出登录状态', self.logout]
        }
        while True:
            for k, v in tmp_dict.items():
                print(k, v[0])
            choice = input('根据序号进行选择').strip()
            if not choice:  # 客户户端不能发送为空的消息
                continue
            if tmp_dict.get(choice):
                tmp_dict.get(choice)[-1]()
            else:
                print('不支持的功能')


if __name__ == '__main__':
    obj = Client('127.0.0.1', 8887)
    obj.handler()

server.py

import os
import socket
import json

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

class Server(object):
    file_path = os.path.join(BASE_DIR, 'user.txt')
    msg_code = {
        200: "register successful",
        # 200: "注册成功",
        201: "user exits",
        300: "login successful",
        301: "user or password error"
    }

    def __init__(self, ip, port):
        self.ip = ip
        self.port = port
        self.sock = socket.socket()
        self.sock.bind((self.ip, self.port), )
        self.sock.listen(5)
        # 如果用户文件不存在,就创建
        if not os.path.isfile(self.file_path):
            open(self.file_path, 'wb').close()


    def register(self, data):
        """ 专门负责注册逻辑的方法 """
        print('register', data)
        f = open(self.file_path, 'r', encoding='utf8')
        for line in f:
            # line: zhangkai|202cb962ac59075b964b07152d234b70
            user, pwd = line.strip().split('|')
            if user == data['user']:  # 该用户已注册
                data['code'] = 201
                data['code_content'] = self.msg_code[201]
                break
        else:  # 表示用户没有注册过,可以正常写文件了
            f.close()
            f = open(self.file_path, 'a', encoding='utf8')
            f.write(f'{data["user"]}|{data["pwd"]}\n')
            f.close()
            data['code'] = 200
            data['code_content'] = self.msg_code[200]

        self.conn.send(json.dumps(data).encode())

    def login(self, data):
        """ 专门负责登录逻辑的方法 """
        print('login', data)
        f = open(self.file_path, 'r', encoding='utf8')
        for line in f:
            # line: zhangkai|202cb962ac59075b964b07152d234b70
            user, pwd = line.strip().split('|')
            if user == data['user'] and pwd == data['pwd']:  # 用户名和密码校验成功
                data['code'] = 300
                data['code_content'] = self.msg_code[300]
                break
        else:  # 用户名或者密码校验失败,需要重新登录
            data['code'] = 301
            data['code_content'] = self.msg_code[301]
        f.close()
        self.conn.send(json.dumps(data).encode())

    def handler(self):
        """
        专门用于跟客户端转发消息的方法
        :return:
        """
        while True:  # 连接循环
            print('等待新客户端的链接....')
            self.conn, addr = self.sock.accept()
            while True:  # 通信循环
                print(f'等待客户端发送消息....')
                try:
                    msg = self.conn.recv(1024).decode()
                    if msg:
                        js_data = json.loads(msg)
                        print(js_data)
                        if hasattr(self, js_data['action_type']):
                            method = getattr(self, js_data['action_type'])
                            method(js_data)
                        else:
                            self.conn.send('不支持的方法'.encode())
                    else:
                        print('客户端退出')
                        break
                except ConnectionResetError as e:
                    print('当前客户端异常断开', e)
                    break
            self.conn.close()

        self.sock.close()


if __name__ == '__main__':
    obj = Server('127.0.0.1', 8887)
    obj.handler()

报头封装版

client.py

import hashlib
import socket
import json
import struct


class Client(object):
    login_status = False

    def __init__(self, ip, port):
        self.ip = ip
        self.port = port
        self.sock = socket.socket()
        self.sock.connect(('127.0.0.1', 8887), )

    def md5(self, pwd):
        """ 专门对密码进行加密,并返回加密后的密码 """
        return hashlib.md5(pwd.encode()).hexdigest()

    def send_msg(self, data):
        """ 将data字典序列化并且传递给对方 """
        head_data = json.dumps(data).encode()
        head_size = struct.pack('i', len(head_data))
        self.sock.send(head_size)
        self.sock.send(head_data)

    def recv_msg(self):
        """ 将对方传过来的报头大小和真实报头解析成字典并返回,它和send_msg搭配使用  """
        head_size = self.sock.recv(4)
        st_head_size = struct.unpack('i', head_size)[0]
        head_data = self.sock.recv(st_head_size)
        return json.loads(head_data.decode())

    def register(self):
        """ 专门负责注册逻辑的方法 """
        while True:
            user = input('user: ').strip()
            pwd = input('pwd: ').strip()
            if not user or not pwd:
                continue
            md_pwd = self.md5(pwd)
            data = {"user": user, "pwd": md_pwd, "action_type": "register"}
            self.send_msg(data)
            msg_data = self.recv_msg()
            if msg_data['code'] == 201:  # 用户已存在
                print(msg_data['code_content'])
            else:  # 注册成功
                print(msg_data['code_content'])
                break

    def login(self):
        """ 专门负责登录逻辑的方法 """
        if self.login_status:
            print('已为你自动登录....')
            return
        while True:
            user = input('user: ').strip()
            pwd = input('pwd: ').strip()
            if not user or not pwd:
                continue
            md_pwd = self.md5(pwd)
            data = {"user": user, "pwd": md_pwd, "action_type": "login"}
            self.send_msg(data)
            msg_data = self.recv_msg()
            if msg_data['code'] == 301:  # 用户名或者密码错误
                print(msg_data['code_content'])
                self.login_status = False
            else:  # 登录成功
                print(msg_data['code_content'])
                self.login_status = True
                break

    def q(self):
        """ 退出程序 """
        exit('你选择退出')

    def logout(self):
        """ 退出登录状态 """
        if self.login_status:
            self.login_status = False
            print(f'当前用户已退出.....')
        else:
            print('用户没有登录')

    def handler(self):
        """
        专门用于跟客户端转发消息的方法
        :return:
        """
        tmp_dict = {
            "1": ['登录', self.login],
            "2": ['注册', self.register],
            "3": ['退出', self.q],
            "4": ['退出登录状态', self.logout]
        }
        while True:
            for k, v in tmp_dict.items():
                print(k, v[0])
            choice = input('根据序号进行选择').strip()
            if not choice:  # 客户户端不能发送为空的消息
                continue
            if tmp_dict.get(choice):
                tmp_dict.get(choice)[-1]()
            else:
                print('不支持的功能')
            # self.sock.send(choice.encode())
            # msg = self.sock.recv(1024).decode()
            # print(msg)


if __name__ == '__main__':
    obj = Client('127.0.0.1', 8887)
    obj.handler()

server.py

import os
import socket
import json
import struct

BASE_DIR = os.path.dirname(os.path.abspath(__file__))


class Server(object):
    file_path = os.path.join(BASE_DIR, 'user.txt')
    msg_code = {
        200: "register successful",
        # 200: "注册成功",
        201: "user exits",
        300: "login successful",
        301: "user or password error"
    }

    def __init__(self, ip, port):
        self.ip = ip
        self.port = port
        self.sock = socket.socket()
        self.sock.bind((self.ip, self.port), )
        self.sock.listen(5)
        # 如果用户文件不存在,就创建
        if not os.path.isfile(self.file_path):
            open(self.file_path, 'wb').close()

    def send_msg(self, data):
        """ 将data字典序列化并且传递给对方 """
        head_data = json.dumps(data).encode()
        head_size = struct.pack('i', len(head_data))
        self.conn.send(head_size)
        self.conn.send(head_data)

    def recv_msg(self):
        """ 将对方传过来的报头大小和真实报头解析成字典并返回,它和send_msg搭配使用 """
        head_size = self.conn.recv(4)
        st_head_size = struct.unpack('i', head_size)[0]
        head_data = self.conn.recv(st_head_size)
        return json.loads(head_data.decode())

    def register(self, data):
        """ 专门负责注册逻辑的方法 """
        print('register', data)
        f = open(self.file_path, 'r', encoding='utf8')
        for line in f:
            # line: zhangkai|202cb962ac59075b964b07152d234b70
            user, pwd = line.strip().split('|')
            if user == data['user']:  # 该用户已注册
                data['code'] = 201
                data['code_content'] = self.msg_code[201]
                break
        else:  # 表示用户没有注册过,可以正常写文件了
            f.close()
            f = open(self.file_path, 'a', encoding='utf8')
            f.write(f'{data["user"]}|{data["pwd"]}\n')
            f.close()
            data['code'] = 200
            data['code_content'] = self.msg_code[200]
        self.send_msg(data)

    def login(self, data):
        """ 专门负责登录逻辑的方法 """
        print('login', data)
        f = open(self.file_path, 'r', encoding='utf8')
        for line in f:
            # line: zhangkai|202cb962ac59075b964b07152d234b70
            user, pwd = line.strip().split('|')
            if user == data['user'] and pwd == data['pwd']:  # 用户名和密码校验成功
                data['code'] = 300
                data['code_content'] = self.msg_code[300]
                break
        else:  # 用户名或者密码校验失败,需要重新登录
            data['code'] = 301
            data['code_content'] = self.msg_code[301]
        f.close()
        self.send_msg(data)

    def handler(self):
        """
        专门用于跟客户端转发消息的方法
        :return:
        """
        while True:  # 连接循环
            print('等待新客户端的链接....')
            self.conn, addr = self.sock.accept()
            while True:  # 通信循环
                print(f'等待客户端发送消息....')
                try:
                    msg_data = self.recv_msg()
                    if msg_data:
                        if hasattr(self, msg_data['action_type']):
                            method = getattr(self, msg_data['action_type'])
                            method(msg_data)
                        else:
                            msg_data['error_msg'] = "不支持的方法"
                            self.send_msg(msg_data)
                    else:
                        print('客户端退出')
                        break
                except Exception as e:
                    print('当前客户端异常断开', e)
                    break
            self.conn.close()
        self.sock.close()


if __name__ == '__main__':
    obj = Server('127.0.0.1', 8887)
    obj.handler()

json类型文件实现版本

client.py

import socket
import json
import hashlib
import struct


class Client(object):
    user_dict = {}

    def __init__(self):
        self.host = '127.0.0.1'
        self.port = 8888
        self.connect_socket()

    def connect_socket(self):
        """绑定IP、端口"""
        self.request = socket.socket()
        self.request.connect((self.host, self.port), )

    def send_msg(self, data):
        """发送数据"""
        head_data = json.dumps(data).encode()
        head_size = struct.pack('i', len(head_data))
        self.request.send(head_size)
        self.request.send(head_data)

    def recv_msg(self):
        """接收数据"""
        head_size = self.request.recv(4)
        st_data = struct.unpack('i', head_size)[0]
        head_data = self.request.recv(st_data).decode()
        return json.loads(head_data)

    def get_md5(self, meg):
        return hashlib.md5(meg.encode()).hexdigest()

    def login(self, ):
        if self.user_dict.get("login_status", False):
            print('自动登录成功.....')
        else:
            while True:
                user, pwd = input('user: ').strip(), input('pwd: ').strip()
                if user and pwd:
                    data = {"user": user, "pwd": self.get_md5(pwd), 'action_type': 'login'}
                    # print(data)
                    self.send_msg(data)
                    recv_data = self.recv_msg()
                    if recv_data.get("status") == 202:
                        print(recv_data.get("content"))
                        self.user_dict = recv_data
                        break
                    else:
                        print(recv_data.get("content"))

    def register(self, ):
        while True:
            user, pwd = input('user: ').strip(), input('pwd: ').strip()
            if user and pwd:
                data = {"user": user, "pwd": self.get_md5(pwd), 'action_type': 'register'}
                # print(data)
                self.send_msg(data)
                recv_data = self.recv_msg()
                if recv_data.get("status") == 201:
                    print(recv_data.get("content"))
                    self.user_dict = recv_data
                    break
                else:
                    print(recv_data.get("content"))

    def q(self, ):
        """ client exit """
        self.send_msg({"action_type": 'q'})
        exit('client exit.......')

    def handler(self, ):
        tmp_dict = {
            "1": ['注册', self.register],
            "2": ['登录', self.login],
            "3": ['退出', self.q],
        }
        while True:
            for k, v in tmp_dict.items():
                print(k, v[0])
            choice = input('根据序号选择操作: ').strip()
            if choice in tmp_dict:
                tmp_dict[choice][-1]()
            else:
                print('输入不合法!!!')


if __name__ == '__main__':
    Client().handler()

server.py

import os
import socket
import json
import struct
from socket import SOL_SOCKET, SO_REUSEADDR
sock = socket.socket()
sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sock.bind(("127.0.0.1", 8888))
sock.listen(5)

class Server(object):
    msg = {
        200: "register error, user exists!",
        201: "register successful",
        202: "login successful",
        203: "login error, user or password error",
    }
    user_info_path = './userinfo.json'
    def __init__(self):
        self.request, addr = sock.accept()
    def read_file(self):
        if not os.path.isfile(self.user_info_path):
            open(self.user_info_path, 'wb').close()
        with open(self.user_info_path, 'r', encoding='utf-8') as f:
            data = f.read()
            if data:
                return json.loads(data)
            else:
                return {}
    def write_file(self, data):
        with open(self.user_info_path, 'w', encoding='utf-8') as f:
            return json.dump(data, f)
    def send_msg(self, data):
        """发送数据"""
        head_data = json.dumps(data).encode()
        head_size = struct.pack('i', len(head_data))
        self.request.send(head_size)
        self.request.send(head_data)
        # sock.send(json.dumps(data).encode())
    def recv_msg(self):
        """接收数据"""
        head_size = self.request.recv(4)
        st_data = struct.unpack('i', head_size)[0]
        head_data = self.request.recv(st_data).decode()
        return json.loads(head_data)
    def q(self, data):
        """ sever端退出 """
        exit('server exit......')
    def login(self, data):
        user_info = self.read_file()
        if data['user'] == user_info.get(data['user'])['user'] and data['pwd'] == user_info.get(data['user'])['pwd']:
            data['status'] = 202
            data['content'] = self.msg[202]
            data['login_status'] = True
        else:
            data['status'] = 203
            data['content'] = self.msg[203]
            data['login_status'] = False
        self.send_msg(data)
    def register(self, data):
        user_info = self.read_file()
        if data['user'] in user_info:
            data['status'] = 200
            data['content'] = self.msg[200]
        else:
            user_info[data['user']] = {"user": data['user'], "pwd": data['pwd']}
            self.write_file(user_info)
            data['status'] = 201
            data['content'] = self.msg[201]
        self.send_msg(data)

    def handler(self):
        while True:
            data = self.recv_msg()
            if hasattr(self, data['action_type']):
                getattr(self, data['action_type'])(data)

if __name__ == '__main__':
    Server().handler()

that's all

posted @ 2022-02-08 15:19  听雨危楼  阅读(567)  评论(0编辑  收藏  举报