今天在之前socket 通信的基础上,使用tpython 自带的tkinter构建了简单的聊天工具,界面相当简陋,只能在局域网下实现双方通信。
平台
- windows10
- python 3.6.5
代码
其实就两个程序,TCPserver.py 和 TCPclient.py,分别实现服务端和客户端的聊天界面,先运行服务端,再运行客户端,客户端运行之后需要输入服务端的ip,本地运行的话使用环回地址即可。
- TCPserver.py
from socket import *
import tkinter as tk
import tkinter.scrolledtext as tst
import time
import tkinter.messagebox
import threading
class Application(tk.Frame):
def __init__(self,master):
tk.Frame.__init__(self,master)
self.grid()
self.createWidgets()
def createWidgets(self):
#显示聊天窗口
self.textEdit=tst.ScrolledText(self,width=50,height=15)
self.textEdit.grid(row=0,column=0,rowspan=1,columnspan=4)
#定义标签,改变字体颜色
self.textEdit.tag_config('server',foreground='red')
self.textEdit.tag_config('guest',foreground='blue')
#编辑窗口
self.inputText=tk.Text(self,width=40,height=5)
self.inputText.grid(row=1,column=0,columnspan=1)
#定义快捷键,按下回车即可发送消息
self.inputText.bind("<KeyPress-Return>",self.textSendReturn)
#发送按钮
self.btnSend=tk.Button(self,text='send',command=self.textSend)
self.btnSend.grid(row=1,column=3)
#开启一个线程用于接收消息并显示在聊天窗口
t=threading.Thread(target=self.getInfo)
t.start()
def textSend(self):
#获取Text的所有内容
str=self.inputText.get('1.0','end-1c')
if str!="" :
#显示发送时间和发送消息
timemsg='服务端'+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())+'\n'
self.textEdit.config(state='normal')
self.textEdit.insert(tk.END,timemsg,'server')
self.textEdit.insert(tk.END,str+'\n')
#将滚动条拉到最后显示最新消息
self.textEdit.see(tk.END)
self.textEdit.config(state='disabled')
self.inputText.delete(0.0,tk.END) #删除输入框的内容
#发送数据到服务端
sendMessage=bytes(str,encoding='utf8')
#发送输入的数据,与UDP有点不同,使用的是send方法,不需要指定服务器和端口,因为已经建立了一条tcp连接
connectionSocket.send(sendMessage)
else:
tk.messagebox.showinfo('警告',"不能发送空白信息!")
def getInfo(self):
while True:
recMsg=connectionSocket.recv(1024).decode("utf-8")+'\n'
revTime='客户端'+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())+'\n'
#通过设置state属性设置textEdit可编辑
self.textEdit.config(state='normal')
self.textEdit.insert(tk.END,revTime,'guest')
self.textEdit.insert(tk.END,recMsg)
#将滚动条拉到最后显示最新消息
self.textEdit.see(tk.END)
#通过设置state属性设置textEdit不可编辑
self.textEdit.config(state='disabled')
def textSendReturn(self,event):
if event.keysym=="Return":
self.textSend()
root=tk.Tk()
root.title('服务端')
#指定服务器使用的端口
serverPort=12000
serverSocket=socket(AF_INET,SOCK_STREAM)
#绑定端口
serverSocket.bind(('',serverPort))
#定义最大连接数
serverSocket.listen(1)
print('等待连接....')
#接受请求则建立一个连接
connectionSocket,addr=serverSocket.accept()
print('一个连接')
app=Application(master=root)
app.mainloop()
- TCPclient.py
from socket import *
import tkinter as tk
import tkinter.scrolledtext as tst
import time
import tkinter.messagebox
import threading
#定义输入服务器ip地址的类
class inputIPdialog(tk.Frame):
def __init__(self,master):
tk.Frame.__init__(self,master)
self.ipInput=tk.Text(self,width=30,height=5)
self.ipInput.grid(row=0,column=0,columnspan=3)
self.okbtn=tk.Button(self,text='确定',command=self.setIP).grid(row=1,column=3)
self.grid()
def setIP(self):
#这个global变量作为类变量的话没有效果,原因不知
global servername
servername=self.ipInput.get('1.0','end-1c')
#销毁窗口
ipRootFrame.destroy()
class Application(tk.Frame):
def __init__(self,master):
tk.Frame.__init__(self,master)
self.grid()
self.createWidgets()
def createWidgets(self):
#显示聊天窗口
self.textEdit=tst.ScrolledText(self,width=50,height=15)
self.textEdit.grid(row=0,column=0,rowspan=1,columnspan=4)
self.textEdit.config(state='disabled')
#定义标签,改变字体颜色
self.textEdit.tag_config('server',foreground='red')
self.textEdit.tag_config('guest',foreground='blue')
#编辑窗口
self.inputText=tk.Text(self,width=40,height=5)
self.inputText.grid(row=1,column=0,columnspan=1)
#定义快捷键,按下回车即可发送消息
self.inputText.bind("<KeyPress-Return>",self.textSendReturn)
#发送按钮
self.btnSend=tk.Button(self,text='send',command=self.textSend)
self.btnSend.grid(row=1,column=3)
#开启一个线程用于接收消息并显示在聊天窗口
t=threading.Thread(target=self.getInfo)
t.start()
def textSend(self):
#获取Text的所有内容
#https://stackoverflow.com/questions/14824163/how-to-get-the-input-from-the-tkinter-text-box-widget
str=self.inputText.get('1.0','end-1c')
if str!="" and str!=None:
#显示发送时间和发送消息
timemsg='客户端'+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())+'\n'
#通过设置state属性设置textEdit可编辑
self.textEdit.config(state='normal')
self.textEdit.insert(tk.INSERT,timemsg,'guest')
self.textEdit.insert(tk.INSERT,str+'\n')
#将滚动条拉到最后显示最新消息
self.textEdit.see(tk.END)
#通过设置state属性设置textEdit不可编辑
self.textEdit.config(state='disabled')
self.inputText.delete(0.0,tk.END) #删除输入框的内容
#发送数据到服务端
sendMessage=bytes(str,encoding='utf8')
#发送输入的数据,与UDP有点不同,使用的是send方法,不需要指定服务器和端口,因为已经建立了一条tcp连接
clientSocket.send(sendMessage)
else:
tk.messagebox.showinfo('警告',"不能发送空白信息!")
def getInfo(self):
global clientSocket
while True:
#接收数据,1024指定缓存长度,使用的是recv方法
recMessage=clientSocket.recv(1024).decode("utf8")+'\n'
#接受时间和接收的数据
recTime='服务端'+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())+'\n'
self.textEdit.config(state='normal')
#server作为标签,改变字体颜色
self.textEdit.insert(tk.END,recTime,'server')
self.textEdit.insert(tk.END,recMessage)
#将滚动条拉到最后显示最新消息
self.textEdit.see(tk.END)
self.textEdit.config(state='disabled')
def textSendReturn(self,event):
if event.keysym=="Return":
self.textSend()
#指定服务器地址,端口
servername=''
serverport=12000
ipRootFrame=tk.Tk()
ipRootFrame.title('输入服务器ip')
ipDialog=inputIPdialog(ipRootFrame)
ipDialog.mainloop()
#socket第一个参数指定使用IPV4协议,第二个参数指定这是一个TCP套接字
clientSocket=None
try:
clientSocket=socket(AF_INET,SOCK_STREAM)
except:
tk.messagebox.showinfo('未知错误','检查服务器地址是否错误!')
#tcp连接需要先经过握手建立连接
clientSocket.connect((servername,serverport))
root=tk.Tk()
root.title('客户端')
app=Application(master=root)
app.mainloop()
界面
- 输入服务端ip
- 聊天界面
缺陷
- 只限制单个连接,只能输入文本
- 不能分列两边显示
- 一切建立在理想情况下,即使发送不出去也会显示在对话框中,没有异常检测并给出处理机制。
- 使用回车发送的话在输入框会残留一个回车符。。
- 太懒了,看以后会不会完善。