利用python socket+tkinter構建簡陋聊天窗口

今天在之前socket 通信的基礎上,使用tpython 自帶的tkinter構建了簡單的聊天工具,界面相當簡陋,只能在局域網下實現雙方通信。

平臺

  • windows10
  • python 3.6.5

代碼

其實就兩個程序,TCPserver.pyTCPclient.py,分別實現服務端和客戶端的聊天界面,先運行服務端,再運行客戶端,客戶端運行之後需要輸入服務端的ip,本地運行的話使用環回地址即可。

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()

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
    服務端ip
  • 聊天界面
    聊天界面

缺陷

  • 只限制單個連接,只能輸入文本
  • 不能分列兩邊顯示
  • 一切建立在理想情況下,即使發送不出去也會顯示在對話框中,沒有異常檢測並給出處理機制。
  • 使用回車發送的話在輸入框會殘留一個回車符。。
  • 太懶了,看以後會不會完善。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章