markdown
# Python Socket 实现一个简单的用户认证系统
这次写的是一个简单的用户认证系统。
整体思路是:
1. 服务端负责保存和校验用户名、密码
2. 客户端负责输入用户名、密码
3. 客户端把用户输入的数据发送给服务端
4. 服务端判断用户名和密码是否正确
5. 服务端把登录结果返回给客户端
这个案例主要用到了三个知识点:
```python
socket
json
文件读取
一、项目结构
这个用户认证系统里面主要有三个文件:
python
用户认证系统
├── client.py
├── server.py
└── 用户名和密码.txt
其中:
python
client.py
是客户端代码,负责让用户输入用户名和密码。
python
server.py
是服务端代码,负责接收客户端发来的数据,并进行认证。
python
用户名和密码.txt
是保存用户名和密码的文件。
文件内容是:
python
zcx 123456
也就是说,目前系统中有一个用户:
python
用户名:zcx
密码:123456
二、服务端代码
服务端代码如下:
python
import socket
import json
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('127.0.0.1', 8001))
server.listen(5)
while True:
conn, addr = server.accept()
print("有客户端来连接了!!!")
conn.sendall("欢迎使用用户认证系统".encode("utf-8"))
while True:
data = conn.recv(1024)
if data == ''.encode("utf-8"):
break
user_dict = json.loads(data.decode("utf-8"))
user_name = user_dict["username"]
user_password = user_dict["password"]
found = False
authenticated = False
with open("用户名和密码.txt", "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
file_username, file_password = line.split(" ")
if file_username == user_name:
found = True
if file_password == user_password:
authenticated = True
break
if found and authenticated:
conn.sendall("登录成功!".encode("utf-8"))
break
elif found and not authenticated:
conn.sendall("密码错误!".encode("utf-8"))
else:
conn.sendall("用户名不存在!".encode("utf-8"))
conn.close()
三、创建 socket 服务端
首先创建一个 socket 对象:
python
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
这里的:
python
socket.AF_INET
表示使用 IPv4 地址。
python
socket.SOCK_STREAM
表示使用 TCP 协议。
TCP 是一种可靠连接,客户端和服务端建立连接之后,就可以互相发送数据。
四、绑定地址和端口
服务端需要绑定 IP 和端口:
python
server.bind(('127.0.0.1', 8001))
这里的:
python
127.0.0.1
表示本机地址。
python
8001
表示端口号。
也就是说,这个服务端运行在本机的 8001 端口上。
然后开始监听:
python
server.listen(5)
表示服务端开始等待客户端连接。
五、等待客户端连接
服务端通过下面这句代码等待客户端连接:
python
conn, addr = server.accept()
当客户端连接成功后,accept() 会返回两个值:
python
conn
表示客户端和服务端之间的连接对象。
python
addr
表示客户端的地址信息。
连接成功之后,服务端会打印:
python
有客户端来连接了!!!
然后给客户端发送欢迎信息:
python
conn.sendall("欢迎使用用户认证系统".encode("utf-8"))
因为网络传输的数据必须是字节类型,所以字符串需要先进行编码:
python
encode("utf-8")
六、接收客户端发来的数据
服务端使用下面这句代码接收客户端数据:
python
data = conn.recv(1024)
这里的 1024 表示一次最多接收 1024 个字节。
客户端发来的数据是 JSON 字符串,所以服务端需要先解码:
python
data.decode("utf-8")
然后再用 json.loads() 转成 Python 字典:
python
user_dict = json.loads(data.decode("utf-8"))
客户端发送的数据格式大概是这样:
python
{
"username": "zcx",
"password": "123456"
}
所以服务端可以这样取出用户名和密码:
python
user_name = user_dict["username"]
user_password = user_dict["password"]
七、读取用户名和密码文件
服务端会打开保存用户名和密码的文件:
python
with open("用户名和密码.txt", "r", encoding="utf-8") as f:
然后一行一行读取:
python
for line in f:
每一行的数据格式是:
python
用户名 密码
比如:
python
zcx 123456
所以可以使用空格分割:
python
file_username, file_password = line.split(" ")
这样就可以拿到文件中的用户名和密码。
八、判断用户名和密码是否正确
代码中定义了两个变量:
python
found = False
authenticated = False
found 表示是否找到了这个用户名。
authenticated 表示密码是否认证成功。
判断逻辑是:
python
if file_username == user_name:
found = True
if file_password == user_password:
authenticated = True
break
如果用户名匹配,就把 found 改成 True。
如果密码也匹配,就把 authenticated 改成 True。
九、返回登录结果
最后根据判断结果,服务端会返回不同的信息。
如果用户名存在,并且密码正确:
python
conn.sendall("登录成功!".encode("utf-8"))
如果用户名存在,但是密码错误:
python
conn.sendall("密码错误!".encode("utf-8"))
如果用户名不存在:
python
conn.sendall("用户名不存在!".encode("utf-8"))
这样客户端就可以根据服务端返回的结果,知道登录是否成功。
十、客户端代码
客户端代码如下:
python
import socket
import json
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 8001))
message = client.recv(1024)
print(message.decode("utf-8"))
while True:
username = input("请输入你的用户名(Q退出):")
if username == "Q":
break
password = input("请输入你的密码(Q退出):")
if password == "Q":
break
user_data = {
"username": username,
"password": password
}
client.sendall(json.dumps(user_data, ensure_ascii=False).encode("utf-8"))
log_message = client.recv(1024)
if log_message.decode("utf-8") == "登录成功!":
print(log_message.decode("utf-8"))
break
else:
print(log_message.decode("utf-8") + "请重新输入(Q退出):")
十一、客户端连接服务端
客户端同样先创建 socket 对象:
python
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
然后连接服务端:
python
client.connect(('127.0.0.1', 8001))
这里连接的是本机的 8001 端口。
所以运行程序时,必须先运行服务端 server.py,再运行客户端 client.py。
连接成功之后,客户端会先接收服务端发来的欢迎信息:
python
message = client.recv(1024)
print(message.decode("utf-8"))
输出结果是:
python
欢迎使用用户认证系统
十二、输入用户名和密码
客户端通过 input() 获取用户输入:
python
username = input("请输入你的用户名(Q退出):")
如果用户输入 Q,就退出程序:
python
if username == "Q":
break
密码也是一样:
python
password = input("请输入你的密码(Q退出):")
然后把用户名和密码放到一个字典中:
python
user_data = {
"username": username,
"password": password
}
十三、使用 JSON 发送数据
字典不能直接通过 socket 发送,所以需要先转成 JSON 字符串:
python
json.dumps(user_data, ensure_ascii=False)
然后再编码成字节:
python
.encode("utf-8")
完整发送代码是:
python
client.sendall(json.dumps(user_data, ensure_ascii=False).encode("utf-8"))
这里的 ensure_ascii=False 是为了让中文能够正常显示,不会被转义成 Unicode 编码。
十四、接收登录结果
客户端发送用户名和密码之后,会等待服务端返回结果:
python
log_message = client.recv(1024)
然后判断是否登录成功:
python
if log_message.decode("utf-8") == "登录成功!":
print(log_message.decode("utf-8"))
break
else:
print(log_message.decode("utf-8") + "请重新输入(Q退出):")
如果服务端返回:
python
登录成功!
客户端打印结果,并退出循环。
如果返回:
python
密码错误!
或者:
python
用户名不存在!
客户端会提示重新输入。
十五、运行流程
运行时需要先启动服务端:
python
python server.py
然后再启动客户端:
python
python client.py
客户端显示:
python
欢迎使用用户认证系统
请输入你的用户名(Q退出):
如果输入:
python
zcx
再输入密码:
python
123456
服务端验证通过,客户端输出:
python
登录成功!
如果用户名正确,但是密码错误,就会输出:
python
密码错误!请重新输入(Q退出):
如果用户名不存在,就会输出:
python
用户名不存在!请重新输入(Q退出):
十六、总结
这个用户认证系统虽然比较简单,但是已经包含了一个客户端和服务端通信的基本流程。
它主要实现了这些功能:
- 服务端监听端口,等待客户端连接
- 客户端连接服务端
- 客户端输入用户名和密码
- 使用 JSON 格式发送用户数据
- 服务端读取本地文件中的用户名和密码
- 服务端判断用户是否存在、密码是否正确
- 服务端把登录结果返回给客户端
这个案例可以帮助我们理解:
python
socket
是如何完成网络通信的。
python
json
是如何在客户端和服务端之间传递结构化数据的。
python
文件读取
是如何用来保存和查询用户信息的。
简单来说,这个项目就是:
python
客户端输入账号密码
↓
通过 socket 发送给服务端
↓
服务端读取文件进行校验
↓
把登录结果返回给客户端
这就是一个最基础版本的 Python 用户认证系统。