基於tcp交互的python聊天程序

語言:Pythonpython

工具:MySQL,Tkinter,圖靈機器人mysql

功能:圖形聊天工具,能夠選擇自動回覆或者人工回覆。sql

注意:若是運行須要自建mysql數據庫表、還有安裝各類模塊、還有到「圖靈機器人」申請帳戶(免費),不然看看就好了。數據庫

(部分借鑑自某個博客,忘記哪裏看的了,tkinter部分和tcp鏈接都是從那裏學來的)django

一、服務器api

#filename:Server+SwitchButton.py
#-*-coding:utf-8-*-

import Tkinter
import tkFont
import socket
import thread
import time
import urllib
import urllib2
import traceback
import MySQLdb
import random
import sys
reload(sys)
sys.setdefaultencoding('utf8')

class Server():
    title = 'Python自動客服-服務器'
    Ip = '127.0.0.1'#還不知怎麼用私網鏈接,目前只能用公網ip設置serverIp
    Port = 8808#端口必須在1024以上
    global serverSock
    global receiveMsg
    global message
    flag = False

    #初始化類的相關屬性,相似於構造方法
    def __init__(self):
        from Tkinter import *
        self.root = Tkinter.Tk()
        self.root.title(self.title)

        #窗口面板,用6個frame面板佈局,ip和port設置框架最後由於鏈接方式的選取問題取消
        self.frame = [Tkinter.Frame(), Tkinter.Frame(), Tkinter.Frame(), Tkinter.Frame(), Tkinter.Frame(), Tkinter.Frame()]

        #frame0
        #切換功能的checkButton
        self.CheckVar1 = IntVar()
        self.CheckVar2 = IntVar()
        self.CheckVar3 = IntVar()
        self.CheckButton1 = Checkbutton(self.frame[0], text = "手動", variable = self.CheckVar1, onvalue = 1, offvalue = 0, height=2, width = 5)
        self.CheckButton2 = Checkbutton(self.frame[0], text = "數據庫", variable = self.CheckVar2, onvalue = 1, offvalue = 0, height=2, width = 5)
        self.CheckButton3 = Checkbutton(self.frame[0], text = "圖靈", variable = self.CheckVar3, onvalue = 1, offvalue = 0, height=2, width = 5)
        self.CheckButton1.pack(expand=1, side=Tkinter.TOP and Tkinter.LEFT)
        self.CheckButton2.pack(expand=1, side=Tkinter.TOP and Tkinter.LEFT)
        self.CheckButton3.pack(expand=1, side=Tkinter.TOP and Tkinter.RIGHT)
        self.frame[0].pack(fill=Tkinter.BOTH)#expand=1,

        '''
        #frame1
        #ip地址和端口選擇,暫時取消
        ft1 = tkFont.Font(family='Fixdsys', size=8)
        self.inputTextIp = Tkinter.Text(self.frame[1], width=20, height=2, font=ft1)
        self.inputTextPort = Tkinter.Text(self.frame[1], width=7, height=2, font=ft1)
        self.ipConfirmButton = Tkinter.Button(self.frame[1], text='確認', width=5, height=2, command=self.setIpPort)
        self.inputTextIp.pack(expand=1, fill=Tkinter.BOTH)
        self.inputTextPort.pack(expand=1, fill=Tkinter.BOTH)
        self.frame[1].pack(expand=1, fill=Tkinter.BOTH)
        '''

        #frame2
        #顯示消息Text右邊的滾動條
        self.chatTextScrollBar = Tkinter.Scrollbar(self.frame[2])
        self.chatTextScrollBar.pack(side=Tkinter.RIGHT, fill=Tkinter.Y)

        #顯示消息Text,並綁定上面的滾動條
        #原本應該相互綁定,但實際運行時,滑動條沒有綁定列表框
        self.chatText = Tkinter.Listbox(self.frame[2], width=80, height=18)
        self.chatText['yscrollcommand'] = self.chatTextScrollBar.set
        self.chatText.pack(expand=1, side=Tkinter.LEFT, fill=Tkinter.BOTH)
        #self.chatTextScrollBar['command'] = self.chatText.yview()
        self.frame[2].pack(fill=Tkinter.BOTH)

        #frame3
        #標籤,建立高度爲2的空白區區分ListBox和Text
        label = Tkinter.Label(self.frame[3], height=2)
        label.pack(fill=Tkinter.BOTH)
        self.frame[3].pack(fill=Tkinter.BOTH)

        #frame4
        #輸入消息Text的滾動條
        self.inputTextScrollBar = Tkinter.Scrollbar(self.frame[4])
        self.inputTextScrollBar.pack(side=Tkinter.RIGHT, fill=Tkinter.Y)

        #輸入消息Text,並與滾動條綁定
        #經常使用字體元組('Arial',('Courier New',),('Comic Sans MS',),'Fixdsys',('MS Sans Serif',),('MS Serif',),'Symbol','System',('Times New Roman',),'Verdana')
        ft4 = tkFont.Font(family='Fixdays', size=11)
        self.inputText = Tkinter.Text(self.frame[4], width=80, height=8, font=ft4)
        self.inputText['yscrollcommand'] = self.inputTextScrollBar.set
        self.inputText.pack(expand=1, fill=Tkinter.BOTH)
        #self.inputTextScrollBar['command'] = self.chatText.yview()
        self.frame[4].pack(fill=Tkinter.BOTH)

        #frame5
        #發送消息按鈕
        self.sendButton = Tkinter.Button(self.frame[5], text=' 發 送 ', width=10, command=self.ManualMessage)#setReplyStatus)#發送按鈕的事件調用設置回覆方式函數
        self.sendButton.pack(expand=1, side=Tkinter.BOTTOM and Tkinter.RIGHT, padx=25, pady=5)

        #關閉按鈕
        self.closeButton = Tkinter.Button(self.frame[5], text=' 關 閉 ', width=10, command=self.close)
        self.closeButton.pack(expand=1, side=Tkinter.RIGHT, padx=25, pady=5)
        self.frame[5].pack(expand=1, fill=Tkinter.BOTH)

        '''
        def showCheckButton1Varialbe(self):
            return self.CheckButton1.variable.get()
        def showCheckButton2Varialbe(self):
            return self.CheckButton2.variable.get()
        '''

    #接收消息並顯示
    def receiveMessage(self):
        global receiveMsg
        #創建Socket鏈接

        try:
            self.serverSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#創建socket,參數爲ipv4,TCP,另外一個參數默認爲1.
            self.serverSock.bind((self.Ip, self.Port))
            self.serverSock.listen(15)
            self.buffer = 1024
            self.chatText.insert(Tkinter.END, '服務器已經就緒......')
        except:
            self.flag = False
            self.chatText.insert(Tkinter.END,'服務器端創建鏈接錯誤,請檢查端口和ip是否可用......')

        try:
            while True:
                #循環接受客戶端的鏈接請求
                self.connection, self.address = self.serverSock.accept()
                self.flag = True
                while True:
                    #循環接收客戶端發送的消息
                    self.clientMsg = self.connection.recv(self.buffer)
                    if not self.clientMsg:
                        #當接受到的clientMsg爲空就跳出循環,出現過卡死狀態
                        continue
                        #能夠講下三次握手:客-》服;服-》客;客-》服
                    elif self.clientMsg == 'Y':
                        self.chatText.insert(Tkinter.END, '服務器端已經與客戶端創建鏈接......')
                        self.connection.send('Y')
                    elif self.clientMsg == 'N':
                        self.chatText.insert(Tkinter.END, '服務器端與客戶端創建鏈接失敗......')
                        self.connection.send('N')
                    else:
                        theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                        self.chatText.insert(Tkinter.END, '客戶端 ' + theTime + ' 說:\n')
                        self.chatText.insert(Tkinter.END, '  ' + self.clientMsg)
                        #self.chatText.insert(Tkinter.END, type(self.clientMsg))
                        try:
                            receiveMsg = self.clientMsg
                        except:
                            print "Error"
                        try:
                            self.setReplyStatus()
                        except:
                            self.chatText.insert(Tkinter.END, '回覆方式函數錯誤......')
        except:
            self.chatText.insert(Tkinter.END, '鏈接錯誤......')


    #判斷回覆方式
    def setReplyStatus(self):
        global replyStatus
        global receiveMsg
        #regard the num as 4,2,1,and add it to replyStatus
        if self.CheckVar1.get()==1 and self.CheckVar2.get()==0 and self.CheckVar3.get()==0:
            self.replyStatus=7
            #此處刪除函數的緣由是,已經設計「發送」按鈕的command調用了ManualMessage,因此在此處定義則調用了兩次函數,而這裏的這個返回空
            #self.ManualMessage()
        #數據庫回覆
        elif self.CheckVar1.get()==0 and self.CheckVar2.get()==1 and self.CheckVar3.get()==0:
            self.replyStatus=2
            try:
                dataInfo=self.DatabaseInformation()
                print "dataInfo:",dataInfo
                #輸入hi時,下面的語句訪問錯誤
                try:
                    self.DatabaseQuestion()
                except:
                    print "hahe181"
                    print "dataQues:",dataQues
                if dataInfo==None and dataQues is not None:

                    self.DatabaseQuestion()
                elif dataInfo==None and dataQues==None:
                    self.chatText.insert(Tkinter.END, '沒法匹配數據庫信息,請手動回覆')
                    self.ManualMessage()
                elif dataInfo is not None and dataQues is None:
                    self.DatabaseInformation()
                #默認兩表不存在交集,因此這部分爲空
                else:
                    pass
            except:
                pass#self.chatText.insert(Tkinter.END, '數據庫回覆錯誤')


        elif self.CheckVar1.get()==0 and self.CheckVar2.get()==0 and self.CheckVar3.get()==1:
            self.replyStatus=1
            self.TuringMessage()


        #數據庫+圖靈回覆
        elif self.CheckVar2.get()==1 and self.CheckVar3.get()==1:
            self.reply=3
            try:
                self.DatabaseInformation()
                if self.DatabaseInformation()==None:
                    self.DatabaseQuestion()
                    if self.DatabaseQuestion()==None:
                        self.TuringMessage()
                        if self.TuringMessage()==None:
                            self.chatText.insert(Tkinter.END, '沒法匹配數據庫信息,請手動回覆')
                            self.ManualMessage()
                    else:
                        self.DatabaseQuestion()
                else:
                    self.DatabaseInformation()
            except:
                self.chatText.insert(Tkinter.END, '數據庫+圖靈回覆錯誤')

        elif self.CheckVar1.get()==1 and self.CheckVar2.get()==0 and self.CheckVar3.get()==1:
            self.replyStatus=1
            self.TuringMessage()
        elif self.CheckVar1.get()==1 and self.CheckVar2.get()==1 and self.CheckVar3.get()==0:
            self.replyStatus=2
            self.DatabaseInformation()
            self.DatabaseQuestion()
        else:
            #格式化當前的時間
            theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
            self.chatText.insert(Tkinter.END,'  ' + '請選擇一種回覆方式,選擇兩種以上都變爲數據庫和圖靈自動回覆(目前狀態)' + '\n')
            #自動切換爲011或者111狀態
            '''
            #爲何這個也錯?暫時放棄
            self.CheckVar2.get()==1
            self.CheckVar3.get()==1
            self.setReplyStatus()
            '''
            '''
            #爲何提示database()訪問有誤,global receiveMsg沒有定義?
            self.reply=3
            if self.DatabaseMessage()==None:
                if self.TuringMessage()==None:
                    theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                    self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
                    self.chatText.insert(Tkinter.END,'  ' + '未能成功匹配,請手動輸入回覆信息' + '\n')
                    self.ManualMessage()
                else:
                    self.TuringMessage()
            else:
                self.DatabaseMessage()
            '''


    '''
    #經過判斷回覆方式獲得將要執行的回覆語句,並由此改變replyStatus的值,再由此函數充當此button的commond函數。暫時放棄。
    def setSendButtonStyle(self):
        if self.replyStatus==7:
            self.ManualMessage()
        elif self.replyStatus==:
            self.ManualMessage()
    '''

    #獲取圖靈消息
    def TuringMessage(self):
        #try:
        #抓取turing的回覆
        global receiveMsg
        global string
        #self.chatText.insert(Tkinter.END, "Hello, I'm Turing. Enter bye to quit.")
        TuringQuestion = receiveMsg.encode('utf-8')#.decode('gb18030')
        try:
            TuringQ = "http://www.tuling123.com/openapi/api?key=dcc40d6323b576076c3005043aaba756&info=%s" %(TuringQuestion)
        except:
            self.chatText.insert(Tkinter.END, "沒法訪問圖靈數據庫1,暫時將調用手動回覆,請輸入......")
            self.manualMessage()
        #print 11111
        try:
            TuringRequest = urllib2.Request(TuringQ)
            print 11111
        except:
            self.chatText.insert(Tkinter.END, "圖靈數據庫提交數據出錯2,暫時將調用手動回覆,請輸入......")
            self.manualMessage()
        #print 22222
        try:
            TuringResponse = urllib2.urlopen(TuringRequest)
            print 22222
        except:
            self.chatText.insert(Tkinter.END, "獲取圖靈數據庫數據錯誤3,暫時將調用手動回覆,請輸入......")
            self.manualMessage()
        TuringAnswer= TuringResponse.read().decode('utf-8')#.encode('gb18030')
        #print 33333
        try:
            #從圖靈獲取的數據是字符串(字典格式的),轉化成字典,並提取text對應的字符串
            string = eval(TuringAnswer)["text"]
            print 33333

        except:
            self.chatText.insert(Tkinter.END, "圖靈數據庫數據轉換錯誤4,沒法輸出,暫時將調用手動回覆,請輸入......")
            self.manualMessage()
        #print 44444
        #if self.flag == True:
        theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
        self.chatText.insert(Tkinter.END,'  ' + string + '\n')
        if self.flag == True:
            self.connection.send(string)
        else:
            self.chatText.insert(Tkinter.END,'您還未與客戶端創建鏈接,客戶端沒法收到您的消息\n')
        #except:
        #return None

    #獲取手動輸入信息
    def ManualMessage(self):
        message = self.inputText.get('1.0',Tkinter.END)
        #格式化當前的時間
        theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
        self.chatText.insert(Tkinter.END,'  ' + message + '\n')
        if self.flag == True:
            #將消息發送到客戶端
            self.connection.send(message)
        else:
            #Socket鏈接沒有創建,提示用戶
            self.chatText.insert(Tkinter.END,'您還未與客戶端創建鏈接,客戶端沒法收到您的消息\n')
        #清空用戶在Text中輸入的消息
        self.inputText.delete(0.0,message.__len__()-1.0)
        '''
        #手動回覆信息,獲得用戶在Text中輸入的消息
        #這個1.0使得get兩次,第一次是未輸入的狀況,get了空,第二次get了輸入的字符串
        string = self.inputText.get('1.0',Tkinter.END)
        print "string:",string
        if string is None:
            pass
        elif self.flag == True and string is not None:
            theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
            print 112
            self.chatText.insert(Tkinter.END,string)
            print 123
            self.connection.send(string)
            print 124
        else:
            self.chatText.insert(Tkinter.END,'您還未與客戶端創建鏈接,客戶端沒法收到您的消息\n')
        #清空用戶在Text中輸入的消息
        self.inputText.delete(0.0,message.__len__()-1.0)
        '''

    #--------------------------------------------------------------
    #數據庫回覆對話信息
    def DatabaseQuestion(self):
        global string
        try:
            #問題出在receiveMsg上!!!
            print 1
            global receiveMsg
            print receiveMsg.strip()
            try:
                conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='n5252n59',db='python',charset='utf8')
            except:
                self.chatText.insert(Tkinter.END, "數據庫鏈接錯誤,請檢查數據庫配置")
            with conn:
                cur = conn.cursor()
                sql = "SELECT * from QuestionAnswerInformation WHERE Question LIKE %s"
                #最痛苦的原來是receiveMsg左右各有一個空格,使用strip()消去,就成了正常字符串
                cur.execute(sql,(receiveMsg.strip(),))
                try:
                    pass
                    #cur.execute(sql,(receiveMsg,))
                    #self.chatText.insert(Tkinter.END, "ha311")
                except:
                    self.chatText.insert(Tkinter.END, "數據庫語句載入錯誤,請檢查數據庫配置")
                try:
                    results=cur.fetchall()
                    #!!!這裏返回爲空!!!???
                    #print 'results:',results
                except:
                    self.chatText.insert(Tkinter.END, "fetch Error 317")
                try:
                    question=results[0][1]
                except:
                    #!!!這句在輸入信息查詢時會輸出,報錯???
                    #self.chatText.insert(Tkinter.END, "fetch Error 362")
                    pass
                #self.chatText.insert(Tkinter.END, question)

                #print question
                answer=results[0][2]

                #self.chatText.insert(Tkinter.END, answer)
                #print "answer:",answer
                LinkToNum=results[0][3]
                #print "LinkToNum:",LinkToNum
                LinkToString=results[0][4]
                #print "LinkToString:",LinkToString

                cur.close()

                '''
                #載入隨機數,判斷經過本詞條回覆,仍是類似詞條(可連接到的)回覆
                randomReply=random.randrange(0,2)
                #print randomReply
                if randomReply is not 0 and answer is not None:
                    string = "%s:%s。" %(question,answer)
                    print string
                else:
                '''
                #!!!3個數據8種回覆方式
                #(任,空,空)當首次查詢的結果爲空時,建立另外一個遊標,獲取linkToNum,並經過Num查找連接向的詞條
                if LinkToNum is None and LinkToString is None:
                    #!!!這裏須要對確切信息和類似信息坐下處理(LIKE和=的區別)
                    #string = "%s:%s。" %(question,answer)
                    #print "您想問的是這個嗎?"
                    if answer is not None:
                        string = "%s。" %(answer)
                        theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                        self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
                        self.chatText.insert(Tkinter.END, string)
                    else:
                        self.chatText.insert(Tkinter.END, "return None from the database,Please use the ManualMessage")

                #(任,非,非)
                elif LinkToNum is not None and LinkToString is not None:
                    self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,不建議連接到字符串和連接到編號同時存在,請檢查數據庫")

                #(任,非,空)
                elif LinkToNum is not None and LinkToString is None:
                    if answer is None:
                        #直接查找連接到的詞條,和下面else後的代碼同樣,可是寫函數就不方便了,因此寫兩個
                        try:
                            curNum = conn.cursor()
                            sqlLinkToNum = "SELECT * from QuestionAnswerInformation WHERE Num = %s"
                        except:
                            self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫1")
                        try:
                            curNum.execute(sqlLinkToNum,(LinkToNum,))
                        except:
                            self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫2")
                        try:
                            resultsNum=curNum.fetchall()
                            string = "%s:%s。" %(resultsNum[0][1],resultsNum[0][2])
                            if resultsNum[0][2] is not None:
                                theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                                self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
                                self.chatText.insert(Tkinter.END, "您想問的是這個嗎?")
                                self.chatText.insert(Tkinter.END, string)
                            else:
                                self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫3")
                        except:
                            self.chatText.insert(Tkinter.END, "return None from the database,Please use the ManualMessage")
                        curNum.close()

                    elif answer is not None:
                        #(非,非,空)(用例是輸入hi)載入隨機數,判斷經過本詞條回覆,仍是類似詞條(可連接到的)回覆
                        randomReply=random.randrange(0,2)
                        #曾經隨機數出過問題,經過print檢驗沒有問題啊
                        #print randomReply
                        if randomReply is not 0:
                            #string = "%s:%s。" %(question,answer)
                            string = "%s。" %(answer)
                            theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                            self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
                            self.chatText.insert(Tkinter.END, string)
                        else:
                            #執行LinkToNum連接到的詞條
                            try:
                                curNum = conn.cursor()
                                sqlLinkToNum = "SELECT * from QuestionAnswerInformation WHERE Num = %s"
                            except:
                                self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫1")
                            try:
                                curNum.execute(sqlLinkToNum,(LinkToNum,))
                            except:
                                self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫2")
                            try:
                                resultsNum=curNum.fetchall()
                                string = "%s。" %(resultsNum[0][2])
                                #string = "%s:%s。" %(resultsNum[0][1],resultsNum[0][2])
                                if resultsNum[0][2] is not None:
                                    #print "您想問的是這個嗎?"
                                    self.chatText.insert(Tkinter.END, string)
                                else:
                                    self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫3")
                            except:
                                self.chatText.insert(Tkinter.END, "return None from the database,Please use the ManualMessage")
                            curNum.close()


                #(任,空,非)連接到字符串
                elif LinkToNum is None and LinkToString is not None:
                    if answer is None:
                        try:
                            curString = conn.cursor()
                            sqlLinkToString = "SELECT * from QuestionAnswerInformation WHERE Question = %s"
                        except:
                            self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫1")

                        curString.execute(sqlLinkToString,(LinkToString,))
                        try:
                            resultsString=curString.fetchall()
                            string = "%s:%s。" %(resultsString[0][1],resultsString[0][2])
                            if resultsString[0][2] is not None:
                                theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                                self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
                                self.chatText.insert(Tkinter.END, "您想問的是這個嗎?")
                                self.chatText.insert(Tkinter.END, string)
                            else:
                                self.chatText.insert(Tkinter.END, "return None from the database,Please use the ManualMessage")
                        except:
                            self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫2")
                        curString.close()
                    elif answer is not None:
                        randomReply=random.randrange(0,2)
                        #print randomReply
                        if randomReply is not 0:

                            #string = "%s:%s。" %(question,answer)
                            string = "%s。" %(answer)
                            theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                            self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
                            self.chatText.insert(Tkinter.END, string)
                        else:
                            try:
                                curString = conn.cursor()
                                sqlLinkToString = "SELECT * from QuestionAnswerInformation WHERE Question = %s"
                            except:
                                self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫1")
                            try:
                                curString.execute(sqlLinkToString,(LinkToString,))
                            except:
                                self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫2")

                            try:
                                resultsString=curString.fetchall()
                                string = "%s:%s。" %(resultsString[0][1],resultsString[0][2])
                            except:
                                self.chatText.insert(Tkinter.END, "數據庫信息輸出錯誤,請檢查數據庫3")
                            if answer is not None:
                                theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                                self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
                                self.chatText.insert(Tkinter.END, "您想問的是這個嗎?")
                                self.chatText.insert(Tkinter.END, string)
                                curString.close()
                            else:
                                self.chatText.insert(Tkinter.END, "return None from the database,Please use the ManualMessage")
                                curString.close()

                #默認linkToString和LinkToNum不能同時不爲空,能夠同時爲空,或者一個爲空
                #if self.flag == True and string is not None:
                if string is not None:
                    self.connection.send(string)
                    #return string
                else:
                    self.chatText.insert(Tkinter.END,'您還未與客戶端創建鏈接,客戶端沒法收到您的消息\n')
        except:
            return None
    #--------------------------------------------------------------


    #數據庫回覆商品信息
    def DatabaseInformation(self):
        '''
        global receiveMsg
        print receiveMsg.strip()
        try:
            conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='n5252n59',db='python',charset='utf8')
        except:
            self.chatText.insert(Tkinter.END, "數據庫鏈接錯誤,請檢查數據庫配置")
        with conn:
            cur = conn.cursor()
            sql = "SELECT * from QuestionAnswerInformation WHERE Question LIKE %s"
            #最痛苦的原來是receiveMsg左右各有一個空格,使用strip()消去,就成了正常字符串
            cur.execute(sql,(receiveMsg.strip(),))
            try:
                pass
                #cur.execute(sql,(receiveMsg,))
                #self.chatText.insert(Tkinter.END, "ha311")
            except:
                self.chatText.insert(Tkinter.END, "數據庫語句載入錯誤,請檢查數據庫配置")
            try:
                results=cur.fetchall()
                #!!!這裏返回爲空!!!???
                print 'results:',results
        '''
        #import MySQLdb
        try:
            global receiveMsg
            #print "receiveMsg:",receiveMsg
            #print "receiveMsg.strip():",receiveMsg.strip()
            #global message
            #theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            #self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
            try:
                conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='n5252n59',db='python',charset='utf8')
            except:
                self.chatText.insert(Tkinter.END, "數據庫鏈接錯誤,請檢查數據庫配置")
            with conn:
                cur = conn.cursor()
                sql="SELECT * from LeatherShoesInformation WHERE ShoesName LIKE %s"
                cur.execute(sql,(receiveMsg.strip(),))
            try:
                results=cur.fetchall()
                print results
            except:
                print "error"
            #cur.execute(sql,(receiveMsg,))
            #lineNum = int(cur.rowcount)
            #databaseReturn = cur.fetchone()[lineNum-1]
            #print databaseReturn

            string1 = "我猜,您正考慮的就是這款皮鞋吧:"
            string2 = "%s,原價:%s,打折後只有:%s。" %(results[0][2],results[0][3],results[0][4])
            string3 = "這款鞋是(%s),(%s)的。" %(results[0][7],results[0][8])
            string4 = "另外,這款鞋是賣家評價%s,%s的優質皮鞋。" %(results[0][12],results[0][10])
            string5 = "若是您想購買這雙皮鞋,咱們還將贈送您%s。咱們建議您,%s。" %(results[0][11],results[0][13])
            string = string1+string2+string3+string4+string5

            theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
            self.chatText.insert(Tkinter.END,string1)
            self.chatText.insert(Tkinter.END,string2)
            self.chatText.insert(Tkinter.END,string3)
            self.chatText.insert(Tkinter.END,string4)
            self.chatText.insert(Tkinter.END,string5)
            cur.close()
            #if self.flag == True:
            #self.sendMessage()
            #這一行若是調用sendMessage(),將只輸出一行
            if self.flag == True:
                self.connection.send(string)
            else:
                self.chatText.insert(Tkinter.END,'您還未與客戶端創建鏈接,客戶端沒法收到您的消息\n')

                #self.connection.send(string2)
                #self.connection.send(string3)
                #self.connection.send(string4)
                #self.connection.send(string5)
        except:
            return

    #6月7日決定註銷這段代碼,將輸出放在函數中進行
    #發送消息,只供manual和turing調用,database的發送方式還沒定
    '''
    def sendMessage(self):
        global message
        theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
        self.chatText.insert(Tkinter.END,'  ' + message + '\n')
        if self.flag == True:
            self.connection.send(message)
        else:
            self.chatText.insert(Tkinter.END,'您還未與客戶端創建鏈接,客戶端沒法收到您的消息\n')
    '''


    #關閉消息窗口並退出
    def close(self):
        sys.exit()

    #啓動線程接收客戶端的消息
    def startNewThread(self):
        #啓動一個新線程來接收客戶端的消息
        #thread.start_new_thread(function,args[,kwargs])函數原型,
        #其中function參數是將要調用的線程函數,args是傳遞給線程函數的參數,它必須是個元組類型,而kwargs是可選的參數
        #receiveMessage函數不須要參數,就傳一個空元組
        thread.start_new_thread(self.receiveMessage, ())
        #thread.start_new_thread(self.setReplyStatus, ())

def main():
    server = Server()
    server.startNewThread()
    server.setReplyStatus()
    server.root.mainloop()


if __name__ == '__main__':
    main()

  

二、客戶端服務器

#filename:TuringTkClient.py
#-*-coding:utf-8-*-
# Python在線聊天客戶端

import Tkinter
import tkFont
import socket
import thread
import time
import sys
reload(sys);
sys.setdefaultencoding('utf8');

class ClientUI():
    
    title = 'Python自動客服-客戶端'
    local = '127.0.0.1'
    port = 8808
    global clientSock;
    flag = False
    
    #初始化類的相關屬性,相似於構造方法
    def __init__(self):
        self.root = Tkinter.Tk()
        self.root.title(self.title)
        
        #窗口面板,用4個面板佈局
        self.frame = [Tkinter.Frame(),Tkinter.Frame(),Tkinter.Frame(),Tkinter.Frame()]

        #顯示消息Text右邊的滾動條
        self.chatTextScrollBar = Tkinter.Scrollbar(self.frame[0])
        self.chatTextScrollBar.pack(side=Tkinter.RIGHT,fill=Tkinter.Y)
        
        #顯示消息Text,並綁定上面的滾動條
        self.chatText = Tkinter.Listbox(self.frame[0],width=80,height=18)
        self.chatText['yscrollcommand'] = self.chatTextScrollBar.set
        self.chatText.pack(expand=1,fill=Tkinter.BOTH)
        self.chatTextScrollBar['command'] = self.chatText.yview()
        self.frame[0].pack(expand=1,fill=Tkinter.BOTH)
        
        #標籤,分開消息顯示Text和消息輸入Text
        label = Tkinter.Label(self.frame[1],height=2)
        label.pack(fill=Tkinter.BOTH)
        self.frame[1].pack(expand=1,fill=Tkinter.BOTH)
        
        #輸入消息Text的滾動條
        self.inputTextScrollBar = Tkinter.Scrollbar(self.frame[2])
        self.inputTextScrollBar.pack(side=Tkinter.RIGHT,fill=Tkinter.Y)
        
        #輸入消息Text,並與滾動條綁定
        ft = tkFont.Font(family='Fixdsys',size=11)
        self.inputText = Tkinter.Text(self.frame[2],width=80,height=8,font=ft)
        self.inputText['yscrollcommand'] = self.inputTextScrollBar.set
        self.inputText.pack(expand=1,fill=Tkinter.BOTH)
        self.inputTextScrollBar['command'] = self.chatText.yview()
        self.frame[2].pack(expand=1,fill=Tkinter.BOTH)
        
        #發送消息按鈕
        self.sendButton=Tkinter.Button(self.frame[3],text=' 發 送 ',width=10,command=self.sendMessage)
        self.sendButton.pack(expand=1,side=Tkinter.BOTTOM and Tkinter.RIGHT,padx=15,pady=8)

        #關閉按鈕
        self.closeButton=Tkinter.Button(self.frame[3],text=' 關 閉 ',width=10,command=self.close)
        self.closeButton.pack(expand=1,side=Tkinter.RIGHT,padx=15,pady=8)
        self.frame[3].pack(expand=1,fill=Tkinter.BOTH)
        
    #接收消息
    def receiveMessage(self):
        try:
            #創建Socket鏈接
            self.clientSock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            self.clientSock.connect((self.local, self.port))
            self.flag = True
        except:
            self.flag = False
            self.chatText.insert(Tkinter.END,'您還未與服務器端創建鏈接,請檢查服務器端是否已經啓動')
            return
            
        self.buffer = 1024
        self.clientSock.send('Y')
        while True:
            try:
                if self.flag == True:
                    #鏈接創建,接收服務器端消息
                    self.serverMsg = self.clientSock.recv(self.buffer)
                    if self.serverMsg == 'Y':
                        self.chatText.insert(Tkinter.END,'客戶端已經與服務器端創建鏈接......')
                    elif self.serverMsg == 'N':
                        self.chatText.insert(Tkinter.END,'客戶端與服務器端創建鏈接失敗......')
                    elif not self.serverMsg:
                        continue
                    else:
                        theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                        self.chatText.insert(Tkinter.END, '服務器 ' + theTime +' 說:\n')
                        self.chatText.insert(Tkinter.END, '  ' + self.serverMsg)
                else:
                    break
            except :
                self.chatText.insert(Tkinter.END,'出現錯誤......')
                self.clientSock.close()
                self.close()
                  
    #發送消息
    def sendMessage(self):
        #狀況1:從text_input獲取用戶輸入
        #獲得用戶在Text中輸入的消息
        message = self.inputText.get('1.0',Tkinter.END)
        #格式化當前的時間
        theTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        self.chatText.insert(Tkinter.END, '客戶端 ' + theTime +' 說:\n')
        self.chatText.insert(Tkinter.END,'  ' + message + '\n')
        if self.flag == True:
            #將消息發送到服務器端
            self.clientSock.send(message);
        else:
            #Socket鏈接沒有創建,提示用戶
            self.chatText.insert(Tkinter.END,'您還未與服務器端創建鏈接,服務器端沒法收到您的消息\n')
        #清空用戶在Text中輸入的消息
        self.inputText.delete(0.0,message.__len__()-1.0)

    #鏈接數據庫並操做
    #def connectDatabaseRequest(self):
        #點擊小提示請求server鏈接數據庫
        #正常打字請求server回覆

    #關閉消息窗口並退出
    def close(self):
        sys.exit()
    
    #啓動線程接收服務器端的消息
    def startNewThread(self):
        #啓動一個新線程來接收服務器端的消息
        #thread.start_new_thread(function,args[,kwargs])函數原型,
        #其中function參數是將要調用的線程函數,args是傳遞給線程函數的參數,它必須是個元組類型,而kwargs是可選的參數
        #receiveMessage函數不須要參數,就傳一個空元組
        thread.start_new_thread(self.receiveMessage,())

def main():
    client = ClientUI()
    client.startNewThread()
    client.root.mainloop()
    
if __name__=='__main__':
    main()

三、效果圖(好大!!!)多線程

四、缺陷:併發

不少,好比tkinter界面太糟糕,交互過程太簡潔並且不合理,沒有認證過程,沒有加入多線程併發等等一大堆問題。框架

甚至有些代碼註釋還沒改,算了,正學django,之後弄一個完整的過程吧。

相關文章
相關標籤/搜索