用Python实现点对点聊天程序,并用tkinter实现简单的软件界面。每一行代码都要注释。
时间: 2023-06-17 18:04:45 浏览: 108
python实现点对点聊天程序
好的,让我们开始吧!
首先,我们需要导入所需的模块:
```python
import socket
import threading
import tkinter as tk
from tkinter import ttk
```
- `socket`模块:用于创建套接字,实现网络连接。
- `threading`模块:用于多线程处理。
- `tkinter`模块:用于创建GUI界面。
- `ttk`模块:包含了一些更现代化的控件。
接下来,我们需要设置一些常量和变量:
```python
HOST = "" # 主机地址
PORT = 5555 # 监听端口号
BUFFER_SIZE = 1024 # 缓冲区大小
# 创建一个套接字对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定主机地址和端口号
server_socket.bind((HOST, PORT))
# 监听客户端连接
server_socket.listen()
# 创建一个字典用于存储客户端套接字对象和用户名
clients = {}
```
- `HOST`:主机地址,这里我们设置为空字符串,表示使用默认的本地IP地址。
- `PORT`:监听端口号,我们设置为5555。
- `BUFFER_SIZE`:缓冲区大小,表示每次接收的数据的字节数。
- `server_socket`:创建一个套接字对象。
- `clients`:用于存储客户端套接字对象和用户名的字典。
接下来,我们需要创建一个函数,用于接收客户端连接:
```python
def accept_client():
while True:
# 接受客户端连接请求
client_socket, client_address = server_socket.accept()
# 请求客户端输入用户名
client_socket.send("Please enter your name:".encode("utf-8"))
username = client_socket.recv(BUFFER_SIZE).decode("utf-8")
# 将客户端套接字对象和用户名添加到字典中
clients[client_socket] = username
# 打印连接信息
print("Accepted connection from {}:{}".format(client_address[0], client_address[1]))
```
该函数用于接收客户端连接,并要求客户端输入用户名,将客户端套接字对象和用户名添加到`clients`字典中,最后打印连接信息。
接下来,我们需要创建一个函数,用于接收客户端消息:
```python
def receive_message(client_socket):
while True:
try:
# 接收客户端发送的消息
message = client_socket.recv(BUFFER_SIZE).decode("utf-8")
# 如果客户端发送的消息为空,则移除该客户端套接字对象和用户名
if message == "":
clients.pop(client_socket)
break
# 遍历字典中的客户端套接字对象和用户名,向除了发送消息的客户端外的所有客户端发送消息
for sock, username in clients.items():
if sock != client_socket:
sock.send("{}: {}".format(username, message).encode("utf-8"))
except:
# 如果发生异常,则移除该客户端套接字对象和用户名
clients.pop(client_socket)
break
```
该函数用于接收客户端发送的消息,并向除了发送消息的客户端外的所有客户端发送消息。如果客户端发送的消息为空,则移除该客户端套接字对象和用户名。如果发生异常,则移除该客户端套接字对象和用户名。
接下来,我们需要创建一个函数,用于启动服务器:
```python
def start_server():
print("Server started...")
# 接受客户端连接请求并创建新线程处理
while True:
client_socket, client_address = server_socket.accept()
threading.Thread(target=accept_client).start()
# 创建新线程处理接收客户端消息
threading.Thread(target=receive_message, args=(client_socket,)).start()
```
该函数用于启动服务器,接受客户端连接请求并创建新线程处理。同时,也会创建新线程处理接收客户端消息。
接下来,我们需要创建GUI界面:
```python
# 创建主窗口
root = tk.Tk()
root.title("Chat Server")
# 创建一个Frame用于显示客户端连接信息
frame1 = ttk.Frame(root, padding="10 10 10 10")
frame1.grid(column=0, row=0, sticky=tk.NSEW)
# 创建一个Label用于显示客户端连接信息
label1 = ttk.Label(frame1, text="No clients connected.", font=("Helvetica", 12))
label1.grid(column=0, row=0, sticky=tk.W)
# 创建一个Frame用于显示聊天记录
frame2 = ttk.Frame(root, padding="10 10 10 10")
frame2.grid(column=0, row=1, sticky=tk.NSEW)
# 创建一个Label用于显示聊天记录
label2 = ttk.Label(frame2, text="Chat history:", font=("Helvetica", 12))
label2.grid(column=0, row=0, sticky=tk.W)
# 创建一个Text用于显示聊天记录
text = tk.Text(frame2, state=tk.DISABLED, font=("Helvetica", 12))
text.grid(column=0, row=1, sticky=tk.NSEW)
# 创建一个Frame用于显示发送消息的控件
frame3 = ttk.Frame(root, padding="10 10 10 10")
frame3.grid(column=0, row=2, sticky=tk.NSEW)
# 创建一个Entry用于输入消息
entry = ttk.Entry(frame3, font=("Helvetica", 12))
entry.grid(column=0, row=0, sticky=tk.NSEW)
# 创建一个Button用于发送消息
button = ttk.Button(frame3, text="Send", command=lambda: send_message(entry.get()))
button.grid(column=1, row=0, sticky=tk.E)
# 设置列权重为1,使得各列自适应大小
root.columnconfigure(0, weight=1)
frame1.columnconfigure(0, weight=1)
frame2.columnconfigure(0, weight=1)
frame3.columnconfigure(0, weight=1)
# 设置行权重为1,使得各行自适应大小
root.rowconfigure(0, weight=1)
root.rowconfigure(1, weight=1)
root.rowconfigure(2, weight=1)
frame1.rowconfigure(0, weight=1)
frame2.rowconfigure(1, weight=1)
frame3.rowconfigure(0, weight=1)
```
该GUI界面包含了三个部分:
- 显示客户端连接信息的Frame
- 显示聊天记录的Frame
- 显示发送消息的控件的Frame
其中,聊天记录使用`Text`控件,输入消息使用`Entry`控件,发送消息使用`Button`控件。
接下来,我们需要创建一个函数,用于发送消息:
```python
def send_message(message):
# 向所有客户端发送消息
for sock, username in clients.items():
sock.send("{}: {}".format("Server", message).encode("utf-8"))
# 将消息添加到聊天记录中
text.configure(state=tk.NORMAL)
text.insert(tk.END, "Server: {}\n".format(message))
text.configure(state=tk.DISABLED)
# 清空输入框
entry.delete(0, tk.END)
```
该函数用于向所有客户端发送消息,并将消息添加到聊天记录中。同时,也会清空输入框。
最后,我们需要将GUI界面与服务器代码连接起来:
```python
# 启动服务器
threading.Thread(target=start_server).start()
# 更新GUI界面
def update_gui():
# 更新客户端连接信息
label1.configure(text="{} clients connected.".format(len(clients)))
for i, (sock, username) in enumerate(clients.items(), start=1):
label1.configure(text="{} clients connected.\n{}: {}".format(len(clients), i, username))
# 更新聊天记录
for i in range(text.index(tk.END).split(".")[0]):
text.delete("{}.0".format(i), "{}.end".format(i))
for message in messages:
text.insert(tk.END, message)
# 每隔500毫秒更新一次GUI界面
root.after(500, update_gui)
# 运行GUI界面
messages = []
update_gui()
root.mainloop()
```
我们使用`threading.Thread`创建一个新线程来启动服务器,然后使用`update_gui`函数更新GUI界面。在每次更新GUI界面时,我们会更新客户端连接信息和聊天记录,并每隔500毫秒更新一次GUI界面。
现在,我们的点对点聊天程序就完成了!完整代码如下:
阅读全文