Python关于服务器与客户端交互,登录验证,删除修改密码等操作的简单实现,自定义协议与协议函数的实现

内容描述

内容及功能

构建客户端。客户端具备的功能有:可以输入客户端的账号和密码,可以选择你所需要的各种功能,可以输入文字和服务器进行交流,可以通过IP及端口号和服务器进行连接,可以自主和服务器断开连接。

构建服务器。服务器具备的功能有:可以连接数据库,可以通过调用数据库验证客户端输入的账号和密码是否正确,密码和账号都正确才可以继续使用,可以通过数据库删除账号,注册账号,修改密码,可以输入文字和客户端进行交流,可以通过IP及端口号和客户端进行连接,服务器一直处于启动中。

目的

通过使用TCP或UDP套接字构建客户端和服务端,搭建数据库,实现在客户端输入账号和密码,在服务器端通过调用数据库进行验证,确认是否正确以便于使用接下来的功能,通过数据库进行对注册账号的保存,删除,和密码修改,还设计了一个服务器和客户端之间互相交流的的程序,总体类似于市面上社交软件的登录和交流功能,主要的目的在于了解在网络中的数据传输和保存,提高对网络安全的认识。

套接字

套接字:在网络中,由IP地址可以唯一确定一台主机,但是准确来说,网络通讯中的双方并不是主机,而是运行在主机上的进程,这样就需要进一步确定是主机中的哪个进程要进行网络通讯。因此,除了IP地址之外,还需要端口号来唯一确定主机中的通讯进程。IP地址和端口号就构成了一个网络中的唯一标识符,即套接字。

套接字用途:Socket被用于客户端/服务端应用框架中。服务端是一个针对客户端的请求执行某些特定操作的进程。大多数应用层协议如FTP、SMTP和POP3使用Socket来建立客户端与服务端之间的连接,从而进行数据的交换。

程序设计概要

程序流程图

在这里插入图片描述

服务器端构建(代码后附)

创建socket实例对象。 

使用bind()方法绑定socket地址。 

listen()开始监听。

accept()接收客户端连接,会阻塞。

与客户端进行读写交互。

关闭连接。

客户端构建(代码后附)

创建Socket实例对象。
connect()连接服务器。
与服务器端进行读写交互。
关闭连接

程序内容及代码

创建数据库

使用Pycharm自带数据库创建一个小型数据库,用来存放和读取用户的账号密码。

create table user
(
  id       nchar(20) not null,
  password nchar(20) not null
);

create unique index user_id_uindex
  on user (id);

定义数据库功能

# 定义数据库类
class Database:
    def __init__(self):
        self.conn = sqlite3.connect('test.db')
        self.c = self.conn.cursor()
    # 查询功能,登录验证调用
    def select(self,id):
        sql = f"select password from user where id='{id}'"
        cursor = self.c.execute(sql)
        for raw in cursor:
            return raw[0]
    # 增加功能,注册功能
    def insert(self,id, password):
        sql = f"insert into user (id,password) values ('{id}','{password}')"
        try:
            self.c.execute(sql)
            self.conn.commit()
            return True
        except:
            self.conn.rollback()
            return False
    # 根据账号上传密码功能,修改密码功能
    def update(self,id,password):
        sql = f"update user set password='{password}' where id='{id}'"
        try:
            self.c.execute(sql)
            self.conn.commit()
            return True
        except:
            print('update error')
            self.conn.rollback()
            return False
    # 删除功能,删除账户功能
    def delete(self,id):
        sql = f"delete from user where id='{id}'"
        try:
            self.c.execute(sql)
            self.conn.commit()
            return True
        except:
            print('delete error')
            self.conn.rollback()
            return False

自定义应用层协议

请求(Request)报文

自定义一个UCCP请求报文,在请求行中,用方法确定所选择的协议函数,UCCP表示协议版本,由于UCCP为自定义协议,故这里只写UCCP;在请求头中,id表示账号,即请求头中的key,password表示密码,也是请求头中的key,请求头中的value就是客户端需要输入的账号密码,这里均用冒号分割成键值对的形式;空白行是请求报头与请求正文的分界,不可省略;请求正文body,空行以后的都是请求正文,可以为空字符串。具体格式如表4.1所示。

​ 表4.1 自定义请求报文格式

请求行方法空格UCCP\r\n
Key(id):{id}\r\n
请求头Key(password):{password}\r\n
…n个请求头信息
空白行\r\n
请求体body

响应(Response)报文

自定义一个UCCP响应报文,在响应行中,以空格为界,分为三个区域,即协议版本、状态码和状态码解释三部分;响应头部均以冒号分割的键值对形式出现;空白行是响应报头和响应数据的分界,不可省略;响应数据body允许为空。具体格式如表4.2所示。

​ 表4.2 自定义响应报文格式

响应行UCCP空格状态码空格状态码解释\r\n
Key:Value\r\n
响应头部Key:Value\r\n
…n个响应头信息
空白行\r\n
响应数据body

UCCP协议函数的方法

​ 表4.3 UCCP协议的方法

方法说明
LOG客户端登陆
MSG获取信息
REG注册信息
CPW修改密码
DEL删除账户
CLS关闭客户端

状态码

状态码状态码解释
100OK,请求成功,服务器端答应了请求
200ERROR,服务器未答应请求

UCCP协议函数方法

# 创建客户端发送协议
def create_request(ty, id, passwd):
    return f'{ty} UCCP {id} {passwd}'

# 创建聊天协议
def create_message(message):
    return f'MSG UCCP {message}'

# 创建返回协议,谁发送谁返回
def create_response(code):
    if code == 100:
        return 'UCCP 100 OK'
    elif code == 200:
        return 'UCCP 200 ERROR'

# 解析客户端发送协议
def analysis_request(mess):
    msl = mess.split(' ')
    ty = msl[0]
    id = msl[2]
    password = msl[3]
    return ty, id, password

# 解析聊天协议
def analysis_message(mess):
    message = mess.split(' ')[2]
    return message

# 解析返回协议
def analysis_response(mess):
    code = mess.split(' ')[1]
    return int(code)

程序编码

客户端(client)编码

from socket import *
from Protocol import *

使用套接字进行构建客户端

def client():
    # 定义一个计数器count
    count = 0
    # 定义一个常量
    i = 3
    # 创建一个Socket实例对象
    Socket = socket(AF_INET, SOCK_STREAM)
    # connect()连接服务器
    Socket.connect(('localhost', 8099)

制作一个选择器,让人们选择所需的功能

# 与服务器端进行读写交互
    while True:
        print('''1.登录聊天\n2.注册账户\n3.修改密码\n4.删除账户\n5.退出\n''')
        tynum = int(input('请选择所需服务:'))
        while tynum > 5 or tynum < 1:
            tynum = int(input('服务选择错误!请重新选择:'))

登录功能

 # 登录功能
        if tynum == 1:
            # 输入客户端账号和密码
            client_number = input("请输入您的客户端账号:")
            client_passwd = input("请输入您的客户端密码:")
            message = create_request('LOG', client_number, client_passwd)
            Socket.send(message.encode('utf8'))
            code = analysis_response(Socket.recv(1024).decode('utf8'))
            if code == 200:
                print('您输入的账户或密码有误,请重新登录。')
                count += 1
                print("剩余输入次数:", i - count)
                if count >= 3:
                    print("你的账户已被锁死!")
                    break
            else:
                print('登陆成功!')

注册功能

# 注册功能
        elif tynum == 2:
            client_number = input("请输入您的客户端账号:")
            while True:
                client_passwd = input("请输入您的客户端密码:")
                if client_passwd != input("请再次输入您的客户端密码:"):
                    print('两次输入密码不一致,请重新输入!')
                else:
                    break
            message = create_request('REG', client_number, client_passwd)
            Socket.send(message.encode('utf8'))
            code = analysis_response(Socket.recv(1024).decode('utf8'))
            if code == 200:
                print('注册成功!')
            else:
                print('注册失败!')

修改密码功能

# 修改密码功能
        elif tynum == 3:  # 修改密码
            client_number = input("请输入您要修改的客户端账号:")
            client_passwd = input("请输入您的客户端新密码:")
            message = create_request('CPW', client_number, client_passwd)
            Socket.send(message.encode('utf8'))
            code = analysis_response(Socket.recv(1024).decode('utf8'))
            if code == 200:
                print('修改成功!')
            else:
                print('修改失败!')

删除账户功能

        elif tynum == 4:
            client_number = input("请输入您要删除的客户端账号:")
            message = create_request('DEL', client_number, '')
            Socket.send(message.encode('utf8'))
            code = analysis_response(Socket.recv(1024).decode('utf8'))
            if code == 200:
                print('删除成功!')
            else:
                print('删除失败!')

退出功能

        elif tynum == 5:
            print('正在关闭。。。')
            message = create_request('CLS', '', '')
            Socket.send(message.encode('utf8'))
            Socket.close()
            break
        else:
            pass

聊天功能

while True:
    # 客户端向服务器发送消息
    data = input('客户:')
    mess = create_message(data)
    Socket.send(mess.encode('utf8'))
    # 判断客户端输入的消息,是bye则断开连接,不是就继续与服务器交互
    if data == 'bye':
        close = analysis_message(Socket.recv(1024).decode('utf8'))
        print('服务:', close)
        break
    else:
        close = analysis_message(Socket.recv(1024).decode('utf8'))
        print('服务:', close)

完整客户端代码

from socket import *
from Protocol import *
def client():
    # 定义一个计数器count
    count = 0
    # 定义一个常量
    i = 3
    # 创建一个Socket实例对象
    Socket = socket(AF_INET, SOCK_STREAM)
    # connect()连接服务器
    Socket.connect(('localhost', 8099))

    # 与服务器端进行读写交互
    while True:
        print('''1.登录聊天\n2.注册账户\n3.修改密码\n4.删除账户\n5.退出\n''')
        tynum = int(input('请选择所需服务:'))
        while tynum > 5 or tynum < 1:
            tynum = int(input('服务选择错误!请重新选择:'))
        # 登录功能
        if tynum == 1:
            # 输入客户端账号和密码
            client_number = input("请输入您的客户端账号:")
            client_passwd = input("请输入您的客户端密码:")
            message = create_request('LOG', client_number, client_passwd)
            Socket.send(message.encode('utf8'))
            code = analysis_response(Socket.recv(1024).decode('utf8'))
            if code == 200:
                print('您输入的账户或密码有误,请重新登录。')
                count += 1
                print("剩余输入次数:", i - count)
                if count >= 3:
                    print("你的账户已被锁死!")
                    break
            else:
                print('登陆成功!')
                while True:
                    # 客户端向服务器发送消息
                    data = input('客户:')
                    mess = create_message(data)
                    Socket.send(mess.encode('utf8'))
                    # 判断客户端输入的消息,是bye则断开连接,不是就继续与服务器交互
                    if data == 'bye':
                        close = analysis_message(Socket.recv(1024).decode('utf8'))
                        print('服务:', close)
                        break
                    else:
                        close = analysis_message(Socket.recv(1024).decode('utf8'))
                        print('服务:', close)
        # 注册功能
        elif tynum == 2:
            client_number = input("请输入您的客户端账号:")
            while True:
                client_passwd = input("请输入您的客户端密码:")
                if client_passwd != input("请再次输入您的客户端密码:"):
                    print('两次输入密码不一致,请重新输入!')
                else:
                    break
            message = create_request('REG', client_number, client_passwd)
            Socket.send(message.encode('utf8'))
            code = analysis_response(Socket.recv(1024).decode('utf8'))
            if code == 200:
                print('注册成功!')
            else:
                print('注册失败!')
        # 修改密码功能
        elif tynum == 3:  # 修改密码
            client_number = input("请输入您要修改的客户端账号:")
            client_passwd = input("请输入您的客户端新密码:")
            message = create_request('CPW', client_number, client_passwd)
            Socket.send(message.encode('utf8'))
            code = analysis_response(Socket.recv(1024).decode('utf8'))
            if code == 200:
                print('修改成功!')
            else:
                print('修改失败!')
        # 删除账户
        elif tynum == 4:
            client_number = input("请输入您要删除的客户端账号:")
            message = create_request('DEL', client_number, '')
            Socket.send(message.encode('utf8'))
            code = analysis_response(Socket.recv(1024).decode('utf8'))
            if code == 200:
                print('删除成功!')
            else:
                print('删除失败!')
        #退出功能
        elif tynum == 5:
            print('正在关闭。。。')
            message = create_request('CLS', '', '')
            Socket.send(message.encode('utf8'))
            Socket.close()
            break
        else:
            pass
client()


服务器(server)编码

引入数据库类、协议

from sqlite import Database
from Protocol import analysis_request, create_response,analysis_message,create_message

定义一个Server()函数,将服务器的功能都封装在函数中

def Server():
......
Server()

接收客户端的需求,账号,密码

ty, id, password =
analysis_request(socket_connect.recv(1024).decode('utf8'))

根据服务器的功能选择所需的操作

if ty == 'LOG':
    Tpassword = db.select(id)
    con = password != Tpassword
    print(f'Result:LOG {con}')
    if con:
        message = create_response(200)
        socket_connect.send(message.encode('utf8'))
    else:
        message = create_response(100)
        socket_connect.send(message.encode('utf8'))
elif ty == 'REG':#注册账户
    con = db.insert(id, password)
    print(f'Result:REG {con}')
    if con:
        message = create_response(200)
        socket_connect.send(message.encode('utf8'))
    else:
        message = create_response(100)
        socket_connect.send(message.encode('utf8'))
elif ty == 'CPW':#修改密码
    con = db.update(id, password)
    print(f'Result:CPW {con}')
    if con:
        message = create_response(200)
        socket_connect.send(message.encode('utf8'))
    else:
        message = create_response(100)
        socket_connect.send(message.encode('utf8'))
elif ty == 'DEL':#删除账户
    con = db.delete(id)
    print(f'Result:DEL {not con}')
    if con:
        message = create_response(200)
        socket_connect.send(message.encode('utf8'))
    else:
        message = create_response(100)
        socket_connect.send(message.encode('utf8'))
elif ty == 'CLS':#关闭服务
    socket_connect.close()
    print(f'close connection: {addr}')
    #重新等待建立连接
    socket_connect, addr = Socket.accept()
    print(f'create connection: {addr}')
else:
    message = create_response(200)
    socket_connect.send(message.encode('utf8'))

与客户端的对话功能

# 与客户端进行读写交互
while True:
    # 接受客户端发送的消息
    recive = analysis_message(socket_connect.recv(1024).decode('utf8'))
    # 打印消息
    print('客户:', recive)
    # 如果接受到的信息为‘拜拜’,则终止程序
    if recive == 'bye':
        data = create_message('bye')
        socket_connect.send(data.encode('utf8'))
        break
    # 服务器向客户端发送消息
    data = create_message(input('服务:'))
    socket_connect.send(data.encode('utf8'))

完整服务器端代码

from socket import *
from sqlite import Database
from Protocol import analysis_request, create_response,analysis_message,create_message


def Server():
    # 创建socket实例对象
    db = Database()
    Socket = socket(AF_INET, SOCK_STREAM)
    # 使用bind()方法绑定socket地址
    Socket.bind(('localhost', 8099))
    # listen()开始监听
    Socket.listen(3)
    print('Server is runing')
    # accept()接收客户端连接,会阻塞
    socket_connect, addr = Socket.accept()
    print(f'create connection: {addr}')

    # 与客户端进行读写交互
    while True:
        ty, id, password = analysis_request(socket_connect.recv(1024).decode('utf8'))
        print(f'Command:{ty} {id} {password}')
        if ty == 'LOG':
            Tpassword = db.select(id)
            con = password != Tpassword
            print(f'Result:LOG {con}')
            if con:
                message = create_response(200)
                socket_connect.send(message.encode('utf8'))
            else:
                message = create_response(100)
                socket_connect.send(message.encode('utf8'))
                # 与客户端进行读写交互
                while True:
                    # 接受客户端发送的消息
                    recive = analysis_message(socket_connect.recv(1024).decode('utf8'))
                    # 打印消息
                    print('客户:', recive)
                    # 如果接受到的信息为‘拜拜’,则终止程序
                    if recive == 'bye':
                        data = create_message('bye')
                        socket_connect.send(data.encode('utf8'))
                        break
                    # 服务器向客户端发送消息
                    data = create_message(input('服务:'))
                    socket_connect.send(data.encode('utf8'))

        elif ty == 'REG':#注册账户
            con = db.insert(id, password)
            print(f'Result:REG {con}')
            if con:
                message = create_response(200)
                socket_connect.send(message.encode('utf8'))
            else:
                message = create_response(100)
                socket_connect.send(message.encode('utf8'))
        elif ty == 'CPW':#修改密码
            con = db.update(id, password)
            print(f'Result:CPW {con}')
            if con:
                message = create_response(200)
                socket_connect.send(message.encode('utf8'))
            else:
                message = create_response(100)
                socket_connect.send(message.encode('utf8'))
        elif ty == 'DEL':#删除账户
            con = db.delete(id)
            print(f'Result:DEL {not con}')
            if con:
                message = create_response(200)
                socket_connect.send(message.encode('utf8'))
            else:
                message = create_response(100)
                socket_connect.send(message.encode('utf8'))
        elif ty == 'CLS':#关闭服务
            socket_connect.close()
            print(f'close connection: {addr}')
            #重新等待建立连接
            socket_connect, addr = Socket.accept()
            print(f'create connection: {addr}')
        else:
            message = create_response(200)
            socket_connect.send(message.encode('utf8'))


Server()

  • 9
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值