使用 Python 编写一个聊天小程序

article/2025/8/25 23:49:10

欢迎关注 “小白玩转Python”,发现更多 “有趣”

本篇文章分享如何用相当简洁的 Python 代码制作一个简单的聊天应用程序。更重要的是,我已经实现了没有任何第三方依赖的代码!

首先,我创建了一个聊天服务器,通过它可以接收来自希望进行通信的客户机的传入请求。为此,我使用了很好的 ole’sockets 和一些多线程。使用像 Twisted 和 SocketServer 这样的框架是一种选择,但是对于像我们这样简单的软件来说,功能似乎有点太庞大了。

服务器

以下是我们如何开始我们的服务器脚本(对于这个应用程序,只有两个脚本:一个用于服务器,另一个用于客户端)):

#!/usr/bin/env python3
"""Server for multithreaded (asynchronous) chat application."""
from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread

为此我们将使用 TCP sockets,因此我们使用 AF_INET 和 SOCK_STREAM 标志。我们通过 UDP sockets 使用它们,因为它们更像电话通讯,在通信开始之前接收者必须批准传入的连接,而 UDP sockets 更像是邮件类型(任何人都可以向任何地址为他/她知道的接收者发送邮件) ,所以它们在通信开始之前并不真正需要建立连接。显然,TCP 比 UDP 更适合我们的目的,因此我们使用它们。

在导入之后,我们设置了一些常量供以后使用:

clients = {}
addresses = {}
HOST = ''
PORT = 33000
BUFSIZ = 1024
ADDR = (HOST, PORT)
SERVER = socket(AF_INET, SOCK_STREAM)
SERVER.bind(ADDR)

现在,我们将服务分解为接受新的连接、广播消息和处理特定的客户端。让我们从接受新的连接开始:

def accept_incoming_connections():"""Sets up handling for incoming clients."""while True:client, client_address = SERVER.accept()print("%s:%s has connected." % client_address)client.send(bytes("Greetings from the cave!"+"Now type your name and press enter!", "utf8"))addresses[client] = client_addressThread(target=handle_client, args=(client,)).start()

这只是一个永远等待传入连接的循环,一旦得到一个连接,它就记录连接(打印一些连接细节)并向连接的客户端发送一条欢迎消息。然后它将客户端的地址存储在字典 addresses 中,然后启动该客户端的处理线程。当然,我们还没有为此定义目标函数 handle_client() ,但是我们是这样做的:

def handle_client(client):  # Takes client socket as argument."""Handles a single client connection."""name = client.recv(BUFSIZ).decode("utf8")welcome = 'Welcome %s! If you ever want to quit, type {quit} to exit.' % nameclient.send(bytes(welcome, "utf8"))msg = "%s has joined the chat!" % namebroadcast(bytes(msg, "utf8"))clients[client] = namewhile True:msg = client.recv(BUFSIZ)if msg != bytes("{quit}", "utf8"):broadcast(msg, name+": ")else:client.send(bytes("{quit}", "utf8"))client.close()del clients[client]broadcast(bytes("%s has left the chat." % name, "utf8"))break

当然,在我们给新客户发送欢迎信息后,它会回复一个他/她想用来进一步交流的名字。在 handle_client()函数中,我们要做的第一个任务是保存这个名称,然后根据进一步的指示向客户机发送另一条消息。在这之后是通信的主循环:在这里我们接收来自客户端的进一步消息,如果消息中没有包含退出指令,我们只需将消息广播给其他连接的客户端(我们将在稍后定义广播方法)。如果我们确实遇到带有退出指令的消息(例如,客户端发送{ quit }) ,我们将相同的消息回发给客户端(它在客户端触发关闭操作) ,然后关闭它的连接套接字。然后,我们通过删除客户端的条目来进行一些清理,最后给这个特定的人已经离开会话的其他联系人一个响应。

现在来看看我们的 broadcast()函数:

def broadcast(msg, prefix=""):  # prefix is for name identification."""Broadcasts a message to all the clients."""for sock in clients:sock.send(bytes(prefix, "utf8")+msg)

这几乎是不言自明的,它只是将 msg 发送给所有连接的客户机,并在必要时添加一个可选的 prefix。我们确实在 handle_client() 函数中为 broadcast() 传递了一个 prefix,我们这样做是为了让人们能够准确地看到特定消息的发送者是谁。

这就是我们服务器所需的全部功能。最后,我们放入一些代码来启动我们的服务器并侦听传入的连接:

if __name__ == "__main__":SERVER.listen(5)  # Listens for 5 connections at max.print("Waiting for connection...")ACCEPT_THREAD = Thread(target=accept_incoming_connections)ACCEPT_THREAD.start()  # Starts the infinite loop.ACCEPT_THREAD.join()SERVER.close()

我们 join() ACCEPT_THREAD,这样主脚本就会等待它完成,而不会跳到下一行,下一行将关闭服务器。

客户端

这是更有趣的,因为我们将编写一个 GUI!我们使用 Tkinter,Python 的“batteries included”GUI 构建工具来实现我们的目的。让我们先做一些导入:

#!/usr/bin/env python3
"""Script for Tkinter GUI chat client."""
from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread
import tkinter

现在我们将编写处理消息发送和接收的函数:

def receive():"""Handles receiving of messages."""while True:try:msg = client_socket.recv(BUFSIZ).decode("utf8")msg_list.insert(tkinter.END, msg)except OSError:  # Possibly client has left the chat.break

为什么又是一个无限循环?因为我们将不确定地接收信息,并且与我们如何以及何时发送信息无关。我们不希望这是一个对讲机聊天应用程序,只能发送或接收在一个时间; 我们希望接收消息时,我们可以,并发送他们当我们想。循环中的功能非常简单; recv()是阻塞部分。它会停止执行,直到它接收到一条消息,当它接收到消息时,我们继续前进,并将消息附加到 msg list 中。我们将很快定义 msg_list,它基本上是 Tkinter 的一个特性,用于在屏幕上显示消息列表。

接下来,我们定义 send() 函数:

def send(event=None):  # event is passed by binders."""Handles sending of messages."""msg = my_msg.get()my_msg.set("")  # Clears input field.client_socket.send(bytes(msg, "utf8"))if msg == "{quit}":client_socket.close()top.quit()

我们使用 event 作为参数,因为当图形用户界面上的 send 按钮被按下时,Tkinter 会隐式地传递事件。my_msg 是 GUI 上的输入字段,因此我们提取要发送给我们的消息 g msg = my_msg.get()。之后,我们清除输入字段,然后将消息发送到服务器,正如我们之前看到的,服务器将此消息广播到所有客户机(如果它不是退出消息)。如果是退出消息,我们关闭 socket,然后关闭 GUI 应用程序(通过 top.close())

我们定义了另一个函数,当我们选择关闭 GUI 窗口时,它将被调用。这是一个类似于关闭前清理的函数,应该在 GUI 关闭前关闭 socket 连接:

def on_closing(event=None):"""This function is to be called when the window is closed."""my_msg.set("{quit}")send()

这将输入字段设置为{ quit } ,然后调用 send() ,这样可以按预期工作。现在我们开始在主命名空间(即任何函数之外)构建 GUI。我们首先定义顶级小部件并设置它的标题:

top = tkinter.Tk()
top.title("Chatter")

然后我们创建一个框架来保存消息列表。接下来,我们创建一个字符串变量,主要用于存储我们从输入字段获得的值(我们将很快定义这个值)。我们将该变量设置为“在这里键入您的消息”提示用户写下他们的信息。然后,我们创建一个滚动条来滚动这个消息框。下面是代码:

messages_frame = tkinter.Frame(top)
my_msg = tkinter.StringVar()  # For the messages to be sent.
my_msg.set("Type your messages here.")
scrollbar = tkinter.Scrollbar(messages_frame)  # To navigate through past messages.

现在我们定义消息列表,它将存储在 messages_frame 中,然后将我们创建的所有内容(在适当的位置)打包:

msg_list = tkinter.Listbox(messages_frame, height=15, width=50, yscrollcommand=scrollbar.set)
scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
msg_list.pack(side=tkinter.LEFT, fill=tkinter.BOTH)
msg_list.pack()
messages_frame.pack()

然后,我们创建输入字段,让用户输入他们的消息,并将其绑定到上面定义的字符串变量。我们还将其绑定到 send()函数,以便每当用户按下 return 键时,消息就被发送到服务器。接下来,如果用户希望通过单击发送消息,我们将创建 send 按钮。同样,我们将单击此按钮绑定到 send()函数。同时我们也包装我们刚刚创建的所有东西。此外,不要忘记使用 on_closing() 的清理函数,当用户希望关闭 GUI 窗口时,应该调用这个函数。我们使用 top 的 protocol 方法来实现。下面是所有这些的代码:

entry_field = tkinter.Entry(top, textvariable=my_msg)
entry_field.bind("<Return>", send)
entry_field.pack()
send_button = tkinter.Button(top, text="Send", command=send)
send_button.pack()
top.protocol("WM_DELETE_WINDOW", on_closing)

现在差不多完成了。我们还没有编写连接到服务器的代码。为此,我们必须向用户询问服务器的地址。我只需要使用 input()就可以做到这一点,因此在 GUI 开始之前,用户会收到一些命令行提示,询问主机地址。这可能有点不方便,您可以为此添加图形用户界面。下面是我的代码:

HOST = input('Enter host: ')
PORT = input('Enter port: ')
if not PORT:PORT = 33000  # Default value.
else:PORT = int(PORT)
BUFSIZ = 1024
ADDR = (HOST, PORT)
client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect(ADDR)

一旦我们得到地址并创建一个 socket 连接到它,我们就开始线程接收消息,然后我们的 GUI 应用程序的主循环:

receive_thread = Thread(target=receive)
receive_thread.start()
tkinter.mainloop()  # Starts GUI execution.

这样!我们已经编写了聊天应用程序。

演示

在多台计算机上进行测试感觉很棒。当然,您可以在同一台机器上运行服务器和客户机进行测试(在客户端中使用127.0.0.1 for HOST) ,但是看到不同计算机之间实时进行通信感觉非常棒。服务器脚本将记录访问它的 IP 地址,客户端脚本将生成一个 GUI (在询问主机地址之后) ,类似于下面的屏幕截图:

客户端 GUI

连接到同一服务器的另一个客户端

·  END  ·

HAPPY LIFE


http://chatgpt.dhexx.cn/article/idCpJIlU.shtml

相关文章

小米手机解BL锁教程

1.找到设置&#xff0c;找到我的设备 2.点击全部参数&#xff0c;多点几下miui版本&#xff0c;直到弹出开发者模式提醒。 3.返回&#xff0c;找到更多设置 4.找到开发者选项 5.找到设备定状态 6.绑定账号和设备&#xff0c;关机&#xff0c;按开键加音量减&#xff0c;进去fas…

安卓搞机玩机-什么是“锁 ” BL锁 屏幕锁 账号锁 设备锁等分析

相信把玩安卓机型的友友们都大概了解机型的锁是什么概念。但有些友友可能还分不清楚具体锁的概念。今天这个帖子由浅入深的带你了解安卓机型中各种“锁”的概念.这类话题比较敏感。只是大概带你分清楚锁的分类和基本对应的解锁方式. 一.屏幕锁【 图案锁 指纹锁 数字锁 人…

万能小米手机解锁,刷机,默认破解BL锁

写在第一条:下载之前请注意 本软件不支持最新机型,只支持4代和4代以前的机型,请注意 早就想给自己的小米手机刷机了&#xff0c;奈何一直没有门&#xff0c;最后还在求助了万能的淘宝&#xff0c;刚刚在淘宝花了 30大洋买的刷机工具&#xff0c;刷机成功之后&#xff0c;才反…

xiaomi 小米 红米redmi 秒解锁BL锁,不用等,在线秒解锁BL工具介绍

xiaomi 小米 红米redmi 秒解锁BL锁,不用等&#xff0c;在线秒解锁BL Xlaomi Redmi K40 Gaming Xlaomt Poco F3 GT Gaming Xaoml Poco X3 GT Xaoml Redmi Note9 5G Xlaomi Redml Note 10 Pro 5G Xlaoml Redmi Note 10 5G Xlaoml Redml Note 10T 5G Xlaoml Poco M3 Pro 5G Xaoml…

小米手机解BL锁、线刷详细教程,适用于小米全系列手机

[教程] 小米手机解BL锁、线刷详细教程&#xff0c;适用于小米全系列手机 这几天看到论坛里很多人在问怎么线刷&#xff0c;下面我就做个详细的线教程大家看一下高手别喷我哈 此教程只适合刷官方MIUI包 进入正题。 第一步&#xff1a;解BL锁 1.浏览器打开申请解锁小米手机点击立…

android@解bl锁@twrp的刷入和使用问题

文章目录 解bl锁步骤 附:MIUI线刷工具待线刷设备扫面和检查使用方式线刷工具卡住的关闭方法 第三方recoverytwrp解密datadata decrypt清除data后用twrp中刷入文件刷入面具 如何找到合适的TWRP rec ref 解bl锁 不是所有android设备都支持解锁下面是以最为典型的MIUI android设备…

02_Lock锁

首先看一下JUC的重磅武器——锁&#xff08;Lock&#xff09; 相比同步锁&#xff0c;JUC包中的Lock锁的功能更加强大&#xff0c;它提供了各种各样的锁&#xff08;公平锁&#xff0c;非公平锁&#xff0c;共享锁&#xff0c;独占锁……&#xff09;&#xff0c;所以使用起来…

红米note10 pro机型解除“账号锁”的一些操作案例 mtk机型强解bl锁

前言。操作解除锁类案例只限于自己的机型&#xff0c; 因手机号长期不用或者忘记密码导致账号锁出现的问题 机型哦 我经常在csdn网站分享一些玩机中的实测资源和玩机常识。遇到很多玩机的友友&#xff0c;其中我分享的一个资源&#xff0c;这个粉丝朋友下载后在网吧操作不了。…

穷举法解华为bl锁

穷举法解华为bl锁 python3代码测试截图 灵感来自于&#xff1a;https://blog.csdn.net/qq_40169767/article/details/90481748 但是我不懂shell脚本&#xff0c;那个脚本又运行不了&#xff0c;所以我用python写了一个&#xff0c; 穷举要0.05s*9999999999999999/60*60*24*3651…

玩机搞机---关于安卓机型工厂固件 刷机 端口解密 解bl锁 写串 nv损坏 等相关常识

*******工程机和工厂固件方面的常识 可能很多玩机友友对什么是工厂固件比较陌生。那么今天的话题就围绕这个和大家讨论下。其实一般厂家的流程都是在一部机型推放市场之前&#xff0c;需要经过预研企划、研发设计、全面测试等诸多环节。在这一整个改善的全过程中&#xff0c;厂…

小米解锁BL锁(普通解锁)

关于BL锁&#xff0c;BootLoader锁&#xff0c;WIKI上的解释简单一点说就是 启动操作系统的软件&#xff0c;也就是引导程序&#xff0c;用于初始化内存等。 官方的说法是防止篡改程序所造成用户的经济和数据损失&#xff0c;网上的说法是可定义程度高&#xff0c;可卸载系统预…

Android系统刷机教程之解bl锁

由于安卓系统是基于linux开发的&#xff0c;属于嵌入式操作系统。在嵌入式操作系统中&#xff0c;BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图&#xff0c;从而将系统的软硬件环境带到一个合适状态&#xff0c;以便为最终调用操作系统内核…

oppo r11 r11t解BL锁安装面具magisk详细教程

OPPO r11 r11t是高通骁龙660处理器&#xff0c;这个系列要解bl锁网上有很多教程比较http://rom点7to点cn/jiaochengdetail/16880 解好BL锁后就可以找三方rec&#xff0c;刷入rec 进入三方rec&#xff0c;把小包发送到手机硬盘&#xff0c;安装小包&#xff0c;再次重启进入三方…

华为手机一键解锁工具箱下载 | 华为手机解BL锁软件: 支持解锁bootloader,刷写recovery功能

文章目录 1. 软件介绍2. 特色功能3. 资源站点4. 下载地址5. 软件截图6. 安装教程7. 使用教程7.1. 解锁BL 1. 软件介绍 通过这款华为手机实用工具箱可以对你的华为手机系列进行刷机、解锁等操作&#xff0c;网上这种华为刷机解锁工具比较少&#xff0c;那么这款华为手机实用工具…

小米手机解bl锁正规方法!

申请解锁小米手机http://www.miui.com/unlock/download.html在手机上打开开发者模式&#xff0c;在开发者模式下-》设备解锁状态 然后关了wifi用手机卡上网绑定设备。 之后在菜单上选择清除所有数据&#xff0c;然后进入系统即可。

[HBZ分享] 小米手机如何解BL锁

第一步&#xff1a; 进入【设置—>我的设备–>全部参数–>连续疯狂的点MIUI版本那一行】 第二步&#xff1a;进入【更多设置–>开发者模式】&#xff0c;打开USB调试 与 USB安装 第三步&#xff1a;进入【更多设置–>开发者模式】&#xff0c;进入【设别解锁状…

9008 能 解锁BL_手机刷入面具及twrp教程(包含解bl锁教程)

原文作者:sgq694243467 原文链接:https://www.52pojie.cn/thread-1288591-1-1.html 最近了买黑鲨3pro 因为miui的广告很烦就想刷面具和xp框架屏蔽广告,但是网上似乎没什么教程,不是要收费就是空壳教程。经过一天测试和查找最终自己刷好了面具 root 和xp框架参考链接 https:…

【小白搞机入门】名词集-BootLoader锁(BL锁)

系列说明&#xff1a;由于作者认识浅薄&#xff0c;很多方面不能解释到十全十美&#xff0c;仅供参考。系列中收录的解决办法并非万能&#xff0c;请谨慎使用。 定义 BootLoader锁&#xff0c;以下简称“BL锁”&#xff0c;从字面意义上理解&#xff0c;是手机厂商对BootLoader…

XMind 8

XMind 8 Update 9 软件管理或官网下载XMind 8 Update 9 下载XMindCrack.jar 文件链接&#xff1a;https://pan.baidu.com/s/1qbI1sMFWBbaQrejI9VUFPQ 提取码&#xff1a;rgba 找到Xmind.ini文件&#xff0c;在Xmind.ini文件尾部追加“-javaagent:文件的绝对路径”&#xff08…