1. 程式人生 > >使用Python實現電子詞典

使用Python實現電子詞典

專案內容:

一、功能說明:

1.使用者可以登入和註冊
	登入憑藉使用者名稱密碼即可
	註冊要求使用者必須填寫使用者名稱和密碼其他內容可自定
	使用者名稱要求不能夠重複

2.使用者資料要求使用資料庫長期儲存
	資料表自定 

3.能夠滿足多個使用者同時登陸操作的需求(多程序多執行緒)

4.功能分為客戶端和服務端,客戶端主要發起請求,服務端處理請求,使用者啟動客戶端即進入一級介面
	一級介面的功能有:登陸、註冊、退出

5.使用者登陸後即進入二級介面
	二級介面內容有:查單詞  檢視歷史記錄 退出
	dict.txt--》每行一個單詞
				單詞和解釋之間一定有空格
				後面的單詞一定比前面的大
	查單詞:輸入單詞,顯示單詞意思,可以迴圈查詢,輸入##表示退出查詞
	檢視歷史記錄:檢視當前使用者的歷史查詞記錄
	name  word  time
	退出:退出到一級介面,相當於登出

二、專案分析

	1.確定技術點
		什麼併發,什麼套接字,什麼資料庫,
		檔案處理還是資料庫查詢,如果是資料庫查詢如何將單詞存入資料庫
		
	2.建立資料表
		建立幾個表  每個表結構  表關係
				3   		使用者資訊    歷史記錄        存單詞

							註冊	   查詢歷史記錄	  查單詞
							登入	   查單詞

	3.專案分析
		伺服器 : 登入  註冊   查詞   歷史記錄
		客戶端 : 列印介面   發出請求    接收反饋   列印結果
		技術點 :   併發   sys.fork
       	套接字  tcp 套接字
  	    資料庫  mysql
   	    查詞    文字
   	    
	4.搭建通訊框架
		工作流程: 建立資料庫,儲存資料 ---》 搭建通訊框架,            
	 		      建立併發關係---》實現具體功能封裝

三、實現

 1.建立資料庫(使用mysql資料庫)

mysql> create database dict default charset=utf8;
mysql> use dict;
Database changed
// 使用者資訊表
mysql> create table user(
    -> id int primary key auto_increment,
    -> name varchar(32) not null,
    -> passwd varchar(16) default '000000');
//歷史記錄表
mysql> create table hist(
    -> id int primary key auto_increment,
    -> name varchar(32) not null,
    -> word varchar(32) not null,
    -> time varchar(64));
//單詞表
//text型別是文字型別,相當於字串一種,比字串大
mysql> create table words(
    -> id int primary key auto_increment,
    -> word varchar(32) not null,
    -> interpret text not null);

2.搭建基本框架

伺服器	建立套接字 --> 建立父子程序 --> 子程序等待處理客戶端請求 
	--> 父程序繼續接收下一個客戶端連線

客戶端	建立套接字 --> 發起連線請求 --> 進入一級介面 --> 請求(登入,註冊,退出)
	--> 登入成功進入二級介面 --> 請求(查詞,歷史記錄)

3.功能實現:
	
	(1)註冊
		客戶端:
			1.輸入註冊資訊
			cookie
			getpass模組:可以隱藏密碼
			getpass.getpass()
			2.將註冊資訊傳送給伺服器
			3.得到伺服器反饋
		服務端:
			1.接收請求
			2.判斷是否允許註冊
			3.將結果反饋給客戶端
			4.註冊資訊插入資料庫

	(2)登入
		客戶端:
			1.輸入登入資訊
			2.將登入資訊傳送給伺服器
			3.得到伺服器的反饋
		服務端:
			1.接收請求
			2.判斷是否可以登入
			3.將結果反饋給客戶端

	(3)查單詞
		客戶端:
			1.輸入單詞
			2.將單詞傳給伺服器
			3.得到伺服器的反饋

		服務端:
			1.接收請求
			2.判斷是否存在這個單詞
			3.將結果反饋給客戶端
			4.將查詢的資訊插入到資料庫

	(4)查詢歷史記錄
		客戶端:
			1.傳送請求
			2.將請求傳給伺服器
			3.得到伺服器的反饋
		服務端:
			1.接收請求
			2.判斷該使用者是否存在歷史記錄
			3.將結果反饋給客戶端

四、程式碼 1.將本地檔案dict.txt中的單詞資訊新增到資料庫

import pymysql
import re

f = open('dict.txt')
db = pymysql.connect("localhost", "root", "123456", "dict")
cursor = db.cursor()

for line in f:
    L = re.split(r"\s\s\s+", line)
    word = L[0]
    interpret = ' '.join(L[1:])
    sql = "insert into words (word,interpret) values('%s','%s')" % (word, interpret)
    try:
        cursor.execute(sql)
        db.commit()
    except Exception:
        db.rollback()
f.close()

2.客戶端實現功能

 #!/usr/bin/python
# coding=utf-8
from socket import *
import sys
import getpass


#二級登入介面
def login(s, name):
	 while True:
    		print('''
        		==========查詢介面============
       		    --1.查詢  2.歷史記錄  3.退出--
        		==============================
       			 ''')

    		try:
        		cmd = int(input("輸入選項>>"))
    		except Exception:
       		    print("命令錯誤")
        	   continue

		    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:
        		print("使用者退出")
       		    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(1024).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("沒有歷史記錄")

# 客戶端-->登入
def do_login(s):
	name = input("User:")
	passwd = getpass.getpass()
	msg = 'L {} {}'.format(name, passwd)
	s.send(msg.encode())
	data = s.recv(1024).decode()
	if data == 'OK':
    	return name
	else:
    	return

# 客戶端-->註冊
def do_register(s):
	while True:
    	name = input("User:")
    	passwd = getpass.getpass()
    	passwd1 = getpass.getpass('Again:')
    	if (' ' in name) or (' ' in passwd):
        	print("使用者名稱和密碼不允許有空格")
        	continue
    	if passwd != passwd1:
        	print("兩次密碼不一致")
        	continue
		msg = 'R {} {}'.format(name, passwd)
    	# 傳送請求
    	s.send(msg.encode())
    	# 等待回覆
    	data = s.recv(1024).decode()
    	if data == 'OK':
        	return name
   	    elif data == 'EXISTS':
       		 return 1
    	else:
        	return 2


# 建立網路連線
def main():
	if len(sys.argv) < 3:
   	 	print("argv is error")
    	return
	HOST = sys.argv[1]
	PORT = int(sys.argv[2])
	s = socket()
	try:
    	s.connect((HOST, PORT))
	except Exception as e:
    	print(e)
    	return

	while True:
    	print('''
        	==========Welcome=========
        	--1.註冊  2.登入  3.退出--
        	==========================
        	''')
    	try:
        	cmd = int(input("輸入選項>>"))
    	except Exception as e:
        	print("命令錯誤")
        	continue
    	if cmd not in [1, 2, 3]:
        	print("請輸入正確選項")
        	sys.stdin.flush()  # 清除標準輸入
    	elif cmd == 1:
        	name = do_register(s)
        	if name:
            	print("註冊成功")
            	login(s, name)
        	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')
        	s.close()
        	sys.exit("謝謝使用")
if __name__ == "__main__":
			 main()

3.服務端實現功能

'''
name:
date:
email:[email protected]
modules:python pymysql...
This is a dict project for AID
'''

from socket import *
import os
import sys
import time
import pymysql
import signal

# 定義需要的全域性變數
DICT_TEXT = './dict.txt'  # 單詞本的位置
HOST = '0.0.0.0'
PORT = 8000
ADDR = (HOST, PORT)

# 接收請求
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("客戶端退出")
    	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]
	passwd = L[2]
	cursor = db.cursor()
	sql = "select * from user where \
        name='%s' and passwd='%s'" % (name, passwd)
	cursor.execute(sql)
	r = cursor.fetchone()
	if r == None:
    	c.send(b'FALL')
    	return
	else:
    	print('%s登入成功' % name)
    	c.send(b'OK')

#服務端-->註冊
def do_register(c, db, data):
	print("註冊操作")
	L = data.split(' ')
	name = L[1]
	passwd = 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,passwd) values\
            ('%s','%s')" % (name, passwd)
	try:
    	cursor.execute(sql)
    	db.commit()
    	c.send(b'OK')
	except Exception:
    	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 Exception:
        	db.rollback()

	sql = "select * from words where word='%s'" % word
	cursor.execute(sql)
	try:
    	f = open(DICT_TEXT)
	except Exception:
    	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'##')


# 流程控制
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)

	while True:
    	try:
        	c, addr = s.accept()
        	print("Connect from", addr)
    	except KeyboardInterrupt:
        	s.close()
        	sys.exit("伺服器退出")
    	except Exception as e:
        	print(e)
        	continue

    	# 建立子程序
    	pid = os.fork()
    	if pid == 0:
        	s.close()
        	# mysql自帶鎖
        	do_child(c, db)
    	else:
        	c.close()
        	continue
if __name__ == "__main__":
	main()

以上僅供參考~