13 網絡編程案例——基於TCP的在線聊天程序(2)

在線聊天程序設計的步驟

1、在線聊天程序的服務器端

## python 在線聊天服務器端
import tkinter
import tkinter.font as tkFont
import socket
import threading
import time, sys


# In[2]:


class ServerUI():
    local = '127.0.0.1'
    port = 5505
    global serverSock
    flag = False
    
    def __init__(self):
        self.root = tkinter.Tk()
        self.root.title('Python在線聊天-服務器端V1.0')
        
        # 窗口面板,用4個frame面板佈局
        self.frame = [tkinter.Frame(), tkinter.Frame(), tkinter.Frame(), tkinter.Frame()]
        
        # 顯示消息Text,並綁定上面的滾動條
        self.chatTextScollBar = tkinter.Scrollbar(self.frame[0])
        self.chatTextScollBar.pack(side=tkinter.RIGHT, fill = tkinter.Y)
        
        # 顯示消息Text,並綁定上面的滾動條
        ft = tkFont.Font(family='Fixdsys', size=11)
        
        self.chatText = tkinter.Listbox(self.frame[0], width = 70, height = 18, font = ft)
        self.chatText['yscrollcommand'] = self.chatTextScollBar.set
        self.chatText.pack(expand = 1, fill = tkinter.BOTH)
        
        self.chatTextScollBar['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 = 70, height = 8, font = ft)
        
        # 輸入消息Text,並與滾動條綁定
        ft = tkFont.Font(family = 'Fixdsys', size = 11)
        self.inputText = tkinter.Text(self.frame[2], width = 70, 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 = 25, pady = 5)
        
        # “關閉”按鈕
        self.closeButton = tkinter.Button(self.frame[3], text = '關閉', width = 10, command = self.close)
        self.closeButton.pack(expand=1, side=tkinter.RIGHT, padx = 25, pady = 5)
        self.frame[3].pack(expand = 1, fill = tkinter.BOTH)
        
    # 接收消息
    def receiveMessage(self):
        # 建立socket連接
        self.serverSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.serverSock.bind((self.local, self.port))
        self.serverSock.listen(15)
        self.buffer = 1024
        self.chatText.insert(tkinter.END, '服務器已經就緒......')
        # 循環接受客戶端的連接請求
        while True:
            self.connection, self.address = self.serverSock.accept()
            self.flag = True
            while True:
                # 接受客戶端發送的消息
                self.cienMsg = self.connection.recv(self.buffer).decode('utf-8')
                if not self.cienMsg:
                    continue
                elif self.cienMsg == 'Y':
                    self.chatText.insert(tkinter.END, '服務器端已經與客戶端建立連接......')
                    self.connection.send(b'Y')
                elif self.cienMsg == 'N':
                    self.chatText.insert(tkinter.END, '服務器端與客戶端建立連接失敗......')
                    self.connection.send(b'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.cienMsg)
            


    # 發送消息
    def sendMessage(self):
        # 得到用戶在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.connection.send(message.encode())
        else:
            # Socket連接沒有建立,提示用戶
            self.chatText.insert(tkinter.END, '您還未與客戶端建立連接, 客戶端無法收到您的消息\n')
        # 清空用戶在Text中輸入的消息
        self.inputText.delete(0.0, message.__len__()-1.0)
        
    # 關閉消息窗口並退出
    def close(self):
        sys.exit()
        
    # 啓動線程接受客戶端的消息
    def startNewThread(self):
        # 啓動一個新線程來接受客戶端的消息
        # args是傳遞給線程函數的參數,receiveMessage函數不需要參數,只傳一個空元組
        thread = threading.Thread(target=self.receiveMessage, args = ())
        thread.setDaemon(True)
        thread.start()

def main1():
    server = ServerUI()
    server.startNewThread()
    server.root.mainloop()
    
            


# In[3]:


main1()

2、在線聊天程序的客戶端

# python 在線聊天客戶端


class ClientUI():
    local = '127.0.0.1'
    port = 5505
    global clientSock
    flag = False
    
    def __init__(self):
        self.root = tkinter.Tk()
        self.root.title('Python在線聊天-客戶端V1.0')
        
        # 窗口面板,用4個frame面板佈局
        self.frame = [tkinter.Frame(), tkinter.Frame(), tkinter.Frame(), tkinter.Frame()]
        
        # 顯示消息Text,並綁定上面的滾動條
        self.chatTextScollBar = tkinter.Scrollbar(self.frame[0])
        self.chatTextScollBar.pack(side=tkinter.RIGHT, fill = tkinter.Y)
        
        # 顯示消息Text,並綁定上面的滾動條
        ft = tkFont.Font(family='Fixdsys', size=11)
        
        self.chatText = tkinter.Listbox(self.frame[0], width = 70, height = 18, font = ft)
        self.chatText['yscrollcommand'] = self.chatTextScollBar.set
        self.chatText.pack(expand = 1, fill = tkinter.BOTH)
        
        self.chatTextScollBar['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 = 70, height = 8, font = ft)
        
        # 輸入消息Text,並與滾動條綁定
        ft = tkFont.Font(family = 'Fixdsys', size = 11)
        self.inputText = tkinter.Text(self.frame[2], width = 70, 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 = 25, pady = 5)
        
        # “關閉”按鈕
        self.closeButton = tkinter.Button(self.frame[3], text = '關閉', width = 10, command = self.close)
        self.closeButton.pack(expand=1, side=tkinter.RIGHT, padx = 25, pady = 5)
        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'.encode()) # 向服務器發送字符Y,表示客戶端要連接服務器
        

        while True:
            try:
                if self.flag == True:
                    # 連接建立,接收服務器端消息
                    self.serverMsg = self.clientSock.recv(self.buffer).decode('utf-8')
                    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 EOFError as msg:
                raise msg
                self.clientSock.close()
                break


    # 發送消息
    def sendMessage(self):
        # 得到用戶在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.encode())
        else:
            # Socket連接沒有建立,提示用戶
            self.chatText.insert(tkinter.END, '您還未與服務器端建立連接, 服務器端無法收到您的消息\n')
        # 清空用戶在Text中輸入的消息
        self.inputText.delete(0.0, message.__len__()-1.0)
        
    # 關閉消息窗口並退出
    def close(self):
        sys.exit()
        
    # 啓動線程接受客戶端的消息
    def startNewThread(self):
        # 啓動一個新線程來接收服務器端的消息
        # args是傳遞給線程函數的參數,receiveMessage函數不需要參數,只傳一個空元組
        thread = threading.Thread(target=self.receiveMessage, args = ())
        thread.setDaemon(True)
        thread.start()

def main2():
    client = ClientUI()
    client.startNewThread()
    client.root.mainloop()
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章