基于tcp交互的python聊天程序
语言:Python
工具:MySQL,Tkinter,图灵机器人
功能:图形聊天工具,可以选择自动回复或者人工回复。
注意:如果运行需要自建mysql数据库表、还有安装各种模块、还有到“图灵机器人”申请账户(免费),否则看看就行了。
(部分借鉴自某个博客,忘记哪里看的了,tkinter部分和tcp连接都是从那里学来的)
1、服务器
#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()
2、客户端
#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()
3、效果图(好大!!!)
4、缺陷:
很多,比如tkinter界面太糟糕,交互过程太简洁而且不合理,没有认证过程,没有加入多线程并发等等一大堆问题。
甚至有些代码注释还没改,算了,正学django,以后弄一个完整的过程吧。
基于tcp交互的python聊天程序的更多相关文章
- JAVA基础知识之网络编程——-基于TCP通信的简单聊天室
下面将基于TCP协议用JAVA写一个非常简单的聊天室程序, 聊天室具有以下功能, 在服务器端,可以接受客户端注册(用户名),可以显示注册成功的账户 在客户端,可以注册一个账号,并用这个账号发送信息 发 ...
- 基于UDP协议的控制台聊天程序(c++版)
本博客由Rcchio原创,转载请告知作者 ------------------------------------------------------------------------------- ...
- 网络编程应用:基于UDP协议【实现聊天程序】--练习
要求: 使用UDP协议实现一个聊天程序 代码: 发送端: package UDP聊天程序; import java.io.IOException; import java.net.DatagramPa ...
- python 聊天程序(基于UDP)
from threading import Thread from socket import * updSocket = socket(AF_INET,SOCK_DGRAM) updSocket.b ...
- 基于Flask框架的Python web程序的开发实战 <一> 环境搭建
最近在看<Flask Web开发基于Python的Web应用开发实战>Miguel Grinberg著.安道译 这本书,一步步跟着学习Flask框架的应用,这里做一下笔记 电脑只安装一个P ...
- 基于TCP/IP的局域网聊天室---C语言
具备注册账号,群聊,查看在线人员信息,私发文件和接收文件功能,因为每个客户端只有一个属于自己的socket,所以无论客户端是发聊天消息还是文件都是通过这一个socket发送, 这也意味着服务器收发任何 ...
- 基于Flask框架的Python web程序的开发实战 <二> 项目组织结构
看到第七章-大型程序的结构,备受打击,搞不清工厂函数.蓝本.单元测试,不理解这些对象/变量怎么传递的,感觉好乱,虽然按照源码都照抄了,还是不理解.... 缓缓先.... 本来网上的Flask的教程就比 ...
- 网络编程应用:基于TCP协议【实现一个聊天程序】
要求: 基于TCP协议实现一个聊天程序,客户端发送一条数据,服务器端发送一条数据 客户端代码: package Homework1; import java.io.IOException; impor ...
- 通过编写聊天程序来熟悉python中多线程及socket的用法
1.引言 Python中提供了丰富的开源库,方便开发者快速就搭建好自己所需要的应用程序.本文通过编写基于tcp/ip协议的通信程序来熟悉python中socket以及多线程的使用. 2.python中 ...
随机推荐
- Linux内核设计笔记14——块I/O层
块I/O层 基本概念 系统中可以随机访问固定大小数据片的硬件设备称做块设备,这些固定大小的数据片称之为块.还有一种基本的设备称之为字符设备,其需要按照顺序访问,比如键盘. 扇区:块设备中最小的寻址单元 ...
- 6.hdfs的存储过程
1.hdfs 怎么存储 切割存储 2. 为何每块是128m 与io读写速度有关,一般人的接受速度1s中,而磁盘的读写速度为100m/s,在读取文件时候需要硬盘寻找地址,一般读懂速度和寻找之间的比例是1 ...
- “Hello World!”团队第三周召开的第五次会议
一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.todo list 六.会议照片 七.燃尽图 八.代码地址 一.会议时间 2017年10月31日 11:45-12:17 二.会议地点: ...
- java利用POI实现读取Word并获取指定样式的文本
import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.hwpf.model.StyleDescription; import o ...
- 算法与数据结构实验题 6.4 Summary
★实验任务 可怜的 Bibi 丢了好几台手机以后,看谁都像是小偷,他已经在小本本上记 下了他认为的各个地点的小偷数量. 现在我们将 Bibi 的家附近的地形抽象成一棵有根树.每个地点都是树上的 一个节 ...
- iOS- 移动端Socket UDP协议广播机制的实现
1.前言 什么是UDP协议广播机制? 举一个例, 例如在一群人群中,一个人要找张三,于是你向人群里大喊一声(广播):“谁是张三” 如果它是张三,它就会回应你,在网络中也是一样的. ...
- lol人物模型提取(七)
9月13号我就把上了贴图的模型文件发了过去,到9月18号他们那的颜色就上好了,一个叫"3d打印旗舰店"的人加了我微信并拍了几张照片发了给我,效果图如下: 第一眼看上去我还是 ...
- struts如何在Action类中操作request,session
在servlet中,通过request.getparameter与setparameter来实现后端与前端jsp页面的数据交互,那么在struts中,也有几种方式来操作request,session实 ...
- VS升级后的配置问题
当vs升级到更新的版本后,运行原来无误的程序会出现一系列问题. 例如:打不开iostream文件,lib文件,系统找不到文件等等 出现这类问题的原因是,编译环境的include path和librar ...
- Jdk1.7 与 jdk1.8的区别,最新的特征有哪些(美团,360,京东面试题目)
在jdk7的新特性方面主要有下面几方面的增强: 1.1二进制变量的表示,支持将整数类型用二进制来表示,用0b开头. 所有整数int.short.long.byte都可以用二进制表示: byte aBy ...