您的位置首页  散文精选

全程干货局域网聊天(局域网聊天系统)

开始更新~!

全程干货局域网聊天(局域网聊天系统)

 

PyQt566篇PyQt5:局域网群聊小工具2导读:正式开篇LEARN MORE正文我们一起来学习下这个小程序吧!整个程序一共大约300行,涉及函数大约23个我们会由浅入深的一起学习1整体架构程序我大致分为6个结构:网络初始化、用户处理、信息处理、格式处理、聊天记录处理、关闭程序。

如下图所示(横着看):

其中网络初始化1个函数、用户处理4个函数、信息处理7个函数、格式处理7个函数、聊天记录处理3个函数、关闭程序2个函数2核心代码解析Message, NewParticipant, ParticipantLeft = range(。

3)在类变量中,我们设定了三个变量,这样也为了区分我们传递的不同信息分别是:消息类型、新用户增加类型、用户离开类型网络初始化defnetworkInit(self):    self.udpSocket = QUdpSocket(self)    self.port = 。

12345    self.udpSocket.bind(self.port, QUdpSocket.ShareAddress | QUdpSocket.ReuseAddressHint)    self.udpSocket.readyRead.connect(self.processPendingDatagrams)    self.sendMessage(Chat.NewParticipant)    currentUser =

"微信公众号:局域网聊天小工具 | 当前用户:{} | IP:{}".format(self.getUserName(), self.getIP())    self.setWindowTitle(currentUser)

这个函数完成网络的初始化设置QUdpSocket类提供UDP套接字UDP(用户数据报协议)是一种轻量级,不可靠,面向数据报的无连接协议当可靠性不重要时,可以使用它QUdpSocket是QAbstractSocket的子类,允许您发送和接收UDP数据报。

使用此类的最常用方法是使用bind()绑定到地址和端口,然后调用writeDatagram()和readDatagram()/ receiveDatagram()来传输数据如果要使用标准QIODevice函数read(),readLine(),write()等,则必须首先通过调用connectToHost()将套接字直接连接到对等方。

每次将数据报写入网络时,套接字都会发出bytesWritten()信号如果您只想发送数据报,则无需调用bind()只要数据报到达,就会发出readyRead()信号在这种情况下,hasPendingDatagrams()返回True。

调用pendingDatagramSize()以获取第一个挂起数据报的大小,并调用readDatagram()或receiveDatagram()来读取它注意:收到readyRead()信号时应读取输入数据报,否则不会为下一个数据报发出此信号。

例:definitSocket(self):    self.udpSocket = QUdpSocket(self)    self.udpSocket.bind(QHostAddress.LocalHost,

7755)    self.udpSocket.readyRead.connect(self.readPendingDatagrams)defreadPendingDatagrams(self):while

self.udpSocket.hasPendingDatagrams():        datagram = self.udpSocket.receiveDatagram()        self.processTheDatagram(datagram)

QUdpSocket还支持UDP多播使用joinMulticastGroup()和leaveMulticastGroup()来控制组成员资格,使用QAbstractSocket. MulticastTtlOption和QAbstractSocket. MulticastLoopbackOption来设置TTL和loopback套接字选项。

使用setMulticastInterface()控制组播数据报的传出接口,使用multicastInterface()查询它使用QUdpSocket,您还可以使用connectToHost()建立到UDP服务器的虚拟连接,然后使用read()和write()交换数据报,而无需为每个数据报指定接收器。

详细的解释请见:https://doc.qt.io/qt-5/qudpsocket.htmlself.port = 12345这个是我们自定义的UDP端口号,你可以随意取,只要不和现有的UDP端口重复就行了。

self.udpSocket.bind(self.port, QUdpSocket.ShareAddress | QUdpSocket.ReuseAddressHint)绑定端口,默认情况下,使用DefaultForPlatform绑定套接字。

如果未指定端口,则选择随机端口绑定方式如下:常数描述QAbstractSocket.ShareAddress允许其他服务绑定到同一地址和端口当多个进程通过侦听相同的地址和端口来共享单个服务的负载时,这很有用(例如,具有多个预分叉侦听器的Web服务器可以大大缩短响应时间)。

但是,由于允许任何服务重新绑定,因此该选项受某些安全性考虑请注意,通过将此选项与ReuseAddressHint组合,您还将允许您的服务重新绑定现有共享地址在Unix上,这相当于SO_REUSEADDR套接字选项。

在Windows上,此选项将被忽略QAbstractSocket.DontShareAddress独占绑定地址和端口,以便不允许其他服务重新绑定通过将此选项传递给QAbstractSocket.bind(),您可以保证在成功时,您的服务是唯一一个侦听地址和端口的服务。

即使它们传递ReuseAddressHint,也不允许重新绑定任何服务此选项提供比ShareAddress更高的安全性,但在某些操作系统上,它要求您以管理员权限运行服务器在Unix和macOS上,不共享是绑定地址和端口的默认行为,因此忽略此选项。

在Windows上,此选项使用SO_EXCLUSIVEADDRUSE套接字选项QAbstractSocket.ReuseAddressHint向QAbstractSocket提供一个提示,即使地址和端口已经被另一个套接字绑定,它也应该尝试重新绑定服务。

在Windows和Unix上,这相当于SO_REUSEADDR套接字选项QAbstractSocket.DefaultForPlatform当前平台的默认选项在Unix和macOS上,这相当于(DontShareAddress + ReuseAddressHint),在Windows上,它相当于ShareAddress。

self.udpSocket.readyRead.connect(self.processPendingDatagrams)每当新数据可用于从设备的当前读取通道读取时,该信号就会发出一次 只有在新数据可用时才会再次发出它,例如网络数据的新有效负载已经到达网络套接字,或者新的数据块已经附加到您的设备上。

readyRead()不是递归发出的; 如果你重新进入事件循环或在连接到readyRead()信号的槽内调用waitForReadyRead(),则不会重新发送信号(尽管waitForReadyRead()仍然可以返回true)。

出现此信号时,我们连接到processPendingDatagrams()函数处理传输的数据self.sendMessage(Chat.NewParticipant)新程序打开时我们发出“新人报到”的消息。

currentUser = "微信公众号:局域网聊天小工具 | 当前用户:{} | IP:{}".format(self.getUserName(), self.getIP()) self.setWindowTitle(currentUser)

将当前用户的用户名、IP地址带入到窗口的标题栏中用户处理defgetIP(self):    addressList = QNetworkInterface.allAddresses()for address 。

in addressList:if address.protocol() == QAbstractSocket.IPv4Protocol and address != QHostAddress.LocalHost

and address.toString()[:3] != "169"and address.toString().split(".")[-1] != "1":return address.toString()    

return"0.0.0.0"QNetworkInterface类提供主机的IP地址和网络接口的列表(list类型)QNetworkInterface表示连接到运行程序的主机的一个网络接口 每个网络接口可以包含零个或多个IP地址,每个IP地址可选地与网络掩码和/或广播地址相关联。

可以使用addressEntries()获得此类三元组的列表 或者,当不需要网络掩码或广播地址或其他信息时,使用allAddresses()便捷功能仅获取活动接口的IP地址QNetworkInterface还使用hardwareAddress()报告接口的硬件地址。

并非所有操作系统都支持报告所有功能 在所有平台中,此类仅保证列出IPv4地址 特别是,IPv6地址列表仅在Windows,Linux,macOS和BSD上受支持for address in addressList:。

if address.protocol() == QAbstractSocket.IPv4Protocol and address != QHostAddress.LocalHost and address.toString()[:

3] != "169"and address.toString().split(".")[-1] != "1":return address.toString()addressList列表中的每个地址是很神奇的,有时会出现一些你自己都想象不到的地址,特别是在安装了VMware虚拟机的电脑上。

要是你的电脑没有安装虚拟机反而简单些,如:fe80::2c0f:90a3:5a61:18dc%ethernet_6 10.20.226.199第一个是IPv6,第二是IPv4address.protocol() == QAbstractSocket.IPv4Protocol。

这里我们只要IPv4的,IPv6的目前还没有普及啊IPv4、IPv6的概念请自行百度address != QHostAddress.LocalHostIP地址我们不要本机地址,如:127.0.0.1address.toString()[:

3] != "169"不要169开头的地址,一般出现这些地址十有八九你的电脑可能是没有配置IP,或者网络有问题address.toString().split(".")[-1] != "1"不要结尾是1的IP地址(可能不准),例如:192.168.100.1,这里地址可能是网关。

剩下的其它地址我们返回如果什么都获取不到返回”0.0.0.0”这种地址defgetUserName(self):    envVariables = ["USERNAME" , "USER" , "HOSTNAME"

, "DOMAINNAME"]    environment = QProcess.systemEnvironment()for var in environment:        varlist = var.split(

"=")        isfide = varlist[0] in envVariablesif isfide:return varlist[1]return"unKnow"该函数用户获取系统中存在的用户名。

environment = QProcess.systemEnvironment()返回系统的环境变量以key = value对的列表的形式返回调用进程的环境 例:environment = QProcess.systemEnvironment()。

#environment = {"PATH=/usr/bin:/usr/local/bin", "USER=greg",  "HOME=/home/greg"}此功能不会缓存系统环境 但请注意,重复调用此函数将重新创建环境变量列表,这是一项非常重要的操作。

注意:对于新代码,建议使用QProcessEnvironment.systemEnvironment()for var in environment:    varlist = var.split("="

)    isfide = varlist[0] in envVariablesif isfide: return varlist[1]要是在系统的环境变量中key值包含envVariables = [“USERNAME” , “USER” , “HOSTNAME” , “DOMAINNAME”]中的任意一个,找到就返回,并将其作为用户名。

要是都找不到则返回”UnKnow”。系统的环境变量很多的,如下图:

这张图我还是只截取了一部分而已。3最后好的,今天介绍就到这里了,下期继续。如果你喜欢本篇文章,请给我点赞

赞赏(推荐

)分享给你的好友们吧!欢迎关注微信公众号:学点编程吧!加油!(ง •̀_•́)ง (*•̀ㅂ•)و点点最下方的广告也是一种支持啊~!

加入我们的学习交流QQ群,一起学习吧!

看完本文有收获?请转发分享给更多人

猜你喜欢:更多的PyQt5文章请在微信公众号/在线课程/图文教程中查找。

免责声明:本站所有信息均搜集自互联网,并不代表本站观点,本站不对其真实合法性负责。如有信息侵犯了您的权益,请告知,本站将立刻处理。联系QQ:1640731186