1. 功能说明
用户可以登录和注册
登录凭借用户名密码即可
注册要求用户必须填写用户名和密码其他内容自定
用户名要求不能重复
用户数据要求使用数据库长期保存
数据表自定
能够满足多个用户同时登录操作的需求
功能分为客户端和服务端,客户端主要发出请求,服务端处理请求
用户启动客户端即进入一级界面
登录 注册 退出
用户登陆后即进入二级界面
查单词 查看历史记录 退出
单词本:每行一个单词
单词和解释之间一定有空格
后面的单词一定比前面的大
查单词:输入单词,显示单词意思,可以循环查询。
输入##表示退出查词
查看历史记录:查看当前用户的历史查词记录
name word time
退出:表示退出到一级界面,相当于注销
2. 过程分析
确定技术点
什么并发 进程线程
什么套接字 流式套接字
什么数据库 mysql
文件处理还是数据库查询 数据库查询
如果是数据库查询如何将单词存入数据库
建立数据表
建立几个表
每个表结构
表关系
3个表 用户信息 历史记录 存单词
注册 查询历史记录 查单词
登陆 查单词
项目分析
仿照ftp和聊天室进行项目分析
搭建通信框架
分析有几个功能,如何封装,每个功能具体实现什么内容
服务端:登陆 注册 查词 历史记录
客户端:打印界面 发出请求 接受反馈 打印结果
技术点:并发(多进程/多线程)
套接字 tcp套接字
数据库 mysql
查词: 文本
工作流程:创建数据库,存储数据
搭建通信框架,建立并发关系
实现具体功能封装
3.过程实现
创建数据库存储数据
dict
user: id name password
hist: id name word time
words:id word interpret
创建数据库
create database dict character set utf8;
创建user表
create table user(id int(10) primary key auto_increment,
name varchar(32) not null,
password varchar(16) default ‘000000’);
创建hist表
create table hist(id int auto_increment primary key,
name varchar(32) not null,
word varchar(32) not null,
time varchar(64));
创建words表
create table words(id int auto_increment primary key,
word varchar(32) not null,
interpret text not null);
搭建基本框架
服务器 创建套接字
创建父子进程
子进程等待处理客户端请求
父进程继续接受下一个客户端连接
客户端 创建套接字
发起连接请求
一级界面
请求(登陆,注册,退出)
登陆成功
进入二级界面
请求(查词,历史记录)
功能实现
注册
客户端
1.输入注册信息
延伸:
密码隐形输入
import getpass
password = getpass.getpass()
功能:隐藏密码输入
2.将注册信息发送给服务器
3.得到服务器反馈
服务端
1.接收请求
2.判断是否允许注册
3.将结果反馈给客户端
4.注册信息插入数据库
登录
客户端
1. 输入登录信息
2. 将用户信息发送给服务器
3. 得到服务器的反馈
4. 跳转到二级界面
服务端
1. 接收请求
2. 判断用户名是否存在
3. 将结果反馈给客户端
查词
客户端
1. 输入要查询的单词
2. 将要查询的单词发送给服务器
3. 得到服务器的反馈
4. 打印得到的反馈
服务端
1. 接收客户端的信息
2. 查询客户端要查询的单词(文本查询)
3. 将用户名和查询单词插入数据库的hist表
4. 将查询结果返回给客户端
查询历史记录
客户端
1. 给服务器发送消息
2. 接收服务端信息
3. 打印消息
服务端
1. 接收客户端信息
2. 根据用户名查询数据库中该用户的历史信息
3. 给结果反馈给客户端
退出
客户端
1. 给服务端发送信息
2. 确认退出
服务端
1. 接收客户端发来的消息
2. 关闭套接字
服务端代码
# dict_server.py
'''
name: lsm
date: 2018-9-28
email: [email protected]
modules: pymysql
'''
from socket import *
import signal
import os
import time
import pymysql
import sys
# 定义需要的全局变量
DICT_TEXT = './dict.txt' # 文件处理
HOST = '0.0.0.0'
PORT = 8000
ADDR = (HOST, PORT)
# 流程控制
def main():
# 创建数据库连接
db = pymysql.connect('localhost', 'root', '123456', 'dict')
# 创建套接字
s = socket()
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(ADDR)
s.listen(5)
# 处理子进程退出(忽略子进程信号)
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
print('Listen the port 8000....')
while True:
try:
c, addr = s.accept()
except KeyboardInterrupt:
s.close()
sys.exit("服务器退出")
except Exception as e:
print('服务器异常:', e)
continue
# 创建子进程
pid = os.fork()
if pid == 0:
s.close()
do_child(c, db)
else:
c.close()
continue
def do_child(c, db):
while True:
data = c.recv(1024).decode()
print(c.getpeername(), ':', data)
if (not data) or data[0] == 'E':
c.close()
sys.exit(0)
elif data[0] == 'R':
do_register(c, db, data)
elif data[0] == 'L':
do_login(c, db, data)
elif data[0] == 'Q':
do_query(c, db, data)
elif data[0] == 'H':
do_hist(c, db, data)
def do_login(c, db, data):
print('登录操作')
l = data.split(' ')
name = l[1]
password = l[2]
cursor = db.cursor()
print(name, password)
sql = "select * from user where name = '%s' and password = '%s'" % (
name, password)
cursor.execute(sql)
r = cursor.fetchone()
if r == None:
c.send(b'FALL')
else:
print('%s登录成功' % name)
c.send(b'OK')
def do_register(c, db, data):
print('注册操作')
l = data.split(' ')
name = l[1]
password = l[2]
cursor = db.cursor()
sql = "select * from user where name = '%s'" % name
cursor.execute(sql)
r = cursor.fetchone()
if r != None:
c.send(b'EXISTS')
return
# 用户不存在插入用户
sql = "insert into user(name,password) values ('%s','%s')" % (
name, password)
try:
cursor.execute(sql)
db.commit()
c.send(b"OK")
except:
db.rollback()
c.send(b'FALL')
else:
print('%s注册成功' % name)
def do_query(c, db, data):
print('查询操作')
l = data.split(' ')
name = l[1]
word = l[2]
cursor = db.cursor()
def insert_history():
tm = time.ctime()
sql = "insert into hist (name,word,time) values('%s','%s','%s')"%(name,word,tm)
try:
cursor.execute(sql)
db.commit()
except:
db.rollback()
# 文本查询
try:
f = open(DICT_TEXT)
except:
c.send(b'FALL')
return
for line in f:
tmp = line.split(' ')[0]
if tmp > word:
c.send(b'FALL')
f.close()
return
elif tmp == word:
c.send(b'OK')
time.sleep(0.1)
c.send(line.encode())
f.close()
insert_history()
return
c.send(b'FALL')
f.close()
def do_hist(c,db,data):
print('历史记录')
l = data.split(' ')
name = l[1]
cursor = db.cursor()
sql = "select * from hist where name = '%s'"%name
cursor.execute(sql)
r = cursor.fetchall()
if not r:
c.send(b'FALL')
return
else:
c.send(b'OK')
for i in r:
time.sleep(0.1)
msg = "%s %s %s"%(i[1],i[2],i[3])
c.send(msg.encode())
time.sleep(0.1)
c.send(b"##")
if __name__ == '__main__':
main()
客户端代码
from socket import *
import sys
import getpass
# 创建网络连接
def main():
if len(sys.argv) < 3:
print('argv is error')
return
HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST, PORT) # 服务器地址
s = socket()
try:
s.connect((HOST, PORT))
except Exception as e:
print(e)
return
while True:
print("================Welcome=================")
print('** 1.注册 2. 登录 3. 退出 **')
print("========================================")
try:
cmd = int(input('请输入选项>>'))
except Exception as e:
print(e)
if cmd not in [1, 2, 3]:
print('请输入正确选项!!!')
# 清除标准输入
sys.stdin.flush()
continue
elif cmd == 1:
name = do_register(s)
if name:
print('注册成功')
login(s, )
elif name == 1:
print('用户存在')
else:
print('注册失败')
elif cmd == 2:
name = do_login(s)
if name:
print('登录成功')
login(s, name)
else:
print('用户名或密码不正确')
elif cmd == 3:
s.send(b'E')
sys.exit("谢谢使用")
def do_register(s):
while True:
name = input("User:")
password = getpass.getpass()
password1 = getpass.getpass("Agin:")
if (' ' in name) or (' ' in password):
print('用户名和密码不允许有空格')
continue
if password != password1:
print('两次密码不一致')
continue
msg = 'R {} {}'.format(name, password)
# 发送请求
s.send(msg.encode())
# 等待回复
data = s.recv(128).decode()
if data == 'OK':
return name
elif data == 'EXISTS':
return 1
else:
return 2
def do_login(s):
name = input("User:")
password = getpass.getpass()
msg = 'L {} {}'.format(name, password)
s.send(msg.encode())
data = s.recv(128).decode()
if data == 'OK':
return name
else:
return
def login(s, name):
while True:
print("================查询界面=================")
print('** 1.查词 2. 历史记录 3. 退出 **')
print("========================================")
try:
cmd = int(input('请输入选项>>'))
except Exception as e:
print(e)
if cmd not in [1, 2, 3]:
print('请输入正确选项!!!')
# 清除标准输入
sys.stdin.flush()
continue
elif cmd == 1:
do_query(s,name)
elif cmd == 2:
do_hist(s,name)
elif cmd == 3:
return
def do_query(s,name):
while True:
word = input("请输入要查询的单词:")
if word == '##':
break
msg = 'Q {} {}'.format(name, word)
s.send(msg.encode())
data = s.recv(128).decode()
if data == 'OK':
data = s.recv(2048).decode()
print(data)
else:
print("没有查到该单词")
def do_hist(s,name):
msg = 'H {}'.format(name)
s.send(msg.encode())
data = s.recv(128).decode()
if data == 'OK':
while True:
data = s.recv(1024).decode()
if data == "##":
break
print(data)
else:
print("没有历史记录")
if __name__ == '__main__':
main()