1. 聊天室介绍
本次实验实现的是在广域网上的聊天室,不同于局域网的聊天室,只要在云服务器上运行服务端脚本,任何一台运行客户端脚本的linux主机都可以进行互发消息。
2. 开发环境
- 服务器:华为云服务器(Ubuntu18.04)。
- 用来测试的客户端:自己的VMware里的两台虚拟机:Ubuntu20.04和Ubuntu18.04。
- 要用到python的Tkinter库。菜鸟教程
- python3网络编程。菜鸟教程
- 服务端开发编辑器:vscode和Remote-ssh插件(这个插件可以实现在vscode中连接到服务器的bash窗口,把文件放到vscode中编辑)。
3. 服务端代码(chat_server.py)实现
chat_server.py
代码倒数第4行的绑定的服务器的IP地址应该是服务器的内网地址,不是公网地址,即</font- 监听TCP:9988端口,并在华为云服务器后台的安全组策略中开放9988端口。
#!/usr/bin/python3
#-*- coding:UTF-8 -*-
import socketserver
class Chat_server(socketserver.StreamRequestHandler):
def handle(self):
conn = self.request
try:
while True:
data_b = conn.recv(1024)
print('data_b = ', data_b)
if conns.count(conn) == 0:
conns.append(conn)
name_s = data_b.decode('utf-8')
users.setdefault(conn, name_s)
data_s = ''
data = 'Welcome' + name_s + '!'
else:
name_s = users.get(conn)
data_s = data_b.decode('utf-8')
data = name_s + ': ' + data_s
print('data = ', data)
data_b = data.encode('utf-8')
for cn in conns:
cn.send(data_b)
if data_s.upper()[0:3] == 'BYE':
print('%s is exited!' % name_s)
conns.remove(conn)
del(users[conn])
break;
except Exception as e:
print('Error is ', e)
conns = []
users = {}
ip = '192.168.0.220' #注意这里是服务器的内网地址不是公网地址
server = socketserver.ThreadingTCPServer((ip, 9988), Chat_server)
print('Wait for TCP connecting...')
server.serve_forever()
4. 客户端代码(chat_client.py)实现
这里的IP地址应该是服务器的公网地址。
#!/usr/bin/python3
# coding:utf-8
import socket
import threading
import tkinter as tk
def send_msg():
txt = bt_txt.get()
if txt == 'Logon':
bt_txt.set('Send')
msg = et_txt.get()
et_txt.set('')
print('msg = ', msg)
msg_b = msg.encode('utf-8')
s.send(msg_b)
if msg.upper()[0:3] == 'BYE':
chat_send.config(state = tk.DISABLED)
s.close()
def receive_msg():
while True:
try:
data_b = s.recv(1024)
data_s = data_b.decode('utf-8')
print('data_s = ', data_s)
chat_list.insert(tk.END, data_s)
chat_list.see(tk.END)
except Exception as e:
print('Error is ', e)
print('Exist!')
break
#ip = '192.168.213.128'
ip = '124.70.13.161'
#ip = 'localhost'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, 9988))
t = threading.Thread(target = receive_msg)
t.start()
root = tk.Tk()
root.title('Chatting room')
root.geometry('300x350')
root.resizable(width = False, height = True)
fm = tk.Frame(root, width=300, height=300)
scrl = tk.Scrollbar(fm)
chat_list = tk.Listbox(fm, width=300, selectmode=tk.BROWSE)
chat_list.configure(yscrollcommand=scrl.set)
scrl['command'] = chat_list.yview
bt_txt = tk.StringVar(value='Logon')
et_txt = tk.StringVar(value='')
chat_txt = tk.Entry(root, bd=5, width=280, textvariable=et_txt)
chat_send = tk.Button(root, textvariable=bt_txt, command=send_msg)
scrl.pack(side=tk.RIGHT, fill=tk.Y)
chat_txt.pack()
chat_send.pack()
chat_list.pack()
fm.pack()
root.mainloop()
5. 测试
- 先在服务器上启动脚本。
sudo chmod +x chat_server.py
sudo ./chat_server.py
- 在客户端1和2上启动客户端脚本
sudo apt-get install python3-tk
sudo chmod +x chat_client.py
sudo ./chat_client.py
- 在客户端上输入消息,第一次输入消息是确定用户的名字。第二次之后就可以正常互发消息了。最后输入bye退出聊天。
客户端:
服务端:
参考资料
- 《Python网络编程(Linux)》清华大学出版社