《Python多人游戏项目实战》第五节 断线重连

news2025/1/11 5:55:26

目录

5.1 模拟弱网状态

5.2 断线重连

5.3 优化玩家名称显示

5.4 完整代码下载地址


导致客户端和服务端断开连接的原因可能有以下三种:

  1. 服务端主动关闭连接。
  2. 客户端窗口关闭,玩家退出游戏。
  3. 客户端所在网络不给力(也叫做弱网),导致延迟或者丢包,严重时掉线。

前两点是正常的断线情况,我们主要来简单了解下针对第三种情况的应对措施,运行结果如下:

注:本节代码是在第三节代码的基础上添加的断线重连功能。

本项目结构显示如下(和第三节中的项目结构一样):

├── SimHei.ttf        # 字体文件
├── client.py         # 客户端代码
├── pics              # 图片文件夹
│   ├── 1.png
│   ├── 2.png
│   ├── 3.png
│   ├── 4.png
│   ├── 5.png
│   └── 6.png
├── player.py         # 包含Player类
└── server.py         # 服务端代码

在player.py中我们新导入了以下模块或库:

import uuid

5.1 模拟弱网状态

当客户端处在弱网状态下的时候,客户端界面会出现卡顿现象(人物移动卡顿,聊天延迟等),严重的话就掉线。我们在GameWindow类中添加一些代码来模拟这种情况:

# client.py
class GameWindow:
    def __init__(self):
        ...

        self.port = 5000
        self.host = "127.0.0.1"
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.is_connected = False              # 1

        self.connect()

    ...

    def connect(self):
        self.sock.connect((self.host, self.port))
        self.player.id = self.sock.recv(2048).decode("utf-8")
        self.is_connected = True              # 2

    def send_player_data(self):
        if not self.is_connected:             # 3
            print("和服务端断开连接")
            self.player.message = ""
            return pickle.dumps({})

        if randint(0, 1000) < 20:             # 4
            print("断线")
            self.sock.close()
            self.is_connected = False
            self.player.message = ""
            return pickle.dumps({})
        elif randint(0, 100) < 10:            # 5
            print("卡顿")
            time.sleep(1)

        data = {
            "id": self.player.id,
            "player": self.player
        }

        self.sock.send(pickle.dumps(data))
        self.player.message = ""
        return self.sock.recv(2048)

    ...

代码解释如下:

1. is_connected变量用来表示客户端和服务端是否连接成功。

2. 如果成功连接,就将is_connected值设为True。

3. 如果客户端和服务端之间的连接断开,就打印断开提示并返回一个空字典的pickle序列化值。

4. 模拟掉线状态,让客户端主动断开连接,并将is_connected值设置为False。

5. 使用time.sleep()函数模拟卡顿状态。

运行结果如下:

首先运行服务端,在运行第一个客户端前,我们先把上面新增的代码注释掉,表示该客户端的网络正常。在运行另一个客户端之前,再把注释取消掉,表示该客户端处在弱网状态下。

右边的客户端处于弱网状态下,笔者在控制人物时会明显感觉到卡顿。掉线之后,其他客户端玩家人物就会从游戏窗口上消失,而该弱网玩家也会在其他玩家的游戏窗口上消失。

5.2 断线重连

当客户端和服务端之间的连接断开后,客户端应该再次发送连接请求。

修改GameWindow类:

# client.py
class GameWindow:
    
    ...
    
    def connect(self):
        try:
            self.sock.connect((self.host, self.port))
        except Exception as e:                 # 3
            print(repr(e))
            print("连接失败,10秒后尝试重新连接。")
            time.sleep(10)
            self.reconnect()
        else:
            self.player.id = self.sock.recv(2048).decode("utf-8")
            self.is_connected = True

    def reconnect(self):                        # 1
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect()

    def send_player_data(self):
        if not self.is_connected:
            print("和服务端断开连接,尝试重新连接")
            self.reconnect()                    # 2
            self.player.message = ""
            return pickle.dumps({})

        ...

    ...

代码解释如下:

1. 在reconnect()函数中,我们重新实例化了一个socket对象并调用connect()方法向服务端发起连接。

2. 和服务端断开连接后,调用reconnect()方法重新连接。

3. 如果因为网络原因连接失败的话,就等10秒后再次尝试连接。

运行结果如下:

 从打印结果可以看出来,当玩家掉线后,客户端与服务端重新连接了,窗口更新还是很卡顿。如果没有个服务端重连,那人物移动是不会卡顿的。

5.3 优化玩家名称显示

如果大家运行了5.2小节中的代码,会发现断线重连后,玩家的id可能会发生改变。这是因为在重连后,服务端的conn对象是新的,而str(id(conn))的值也可能和断线前的不一样。

注:当然在游戏中应该显示玩家自定义的名称,如果是这样的话,那重连后不会有这个名称变换的问题,因为玩家名称都是根据玩家账号从数据库中获取的。

为了简单起见,我们就在Player类中添加一个name属性,这个就当做玩家自定义的名称。

修改Player类:

# player.py
class Player:
    def __init__(self, p_id, x, y,  pic_num, frame_width, frame_height):
        ...

        self.message = ""
        self.name = f"葬爱{uuid.uuid4()}"                           # 1

    ...

    def draw(self, win, pic):
        win.blit(pic, (self.x, self.y), self.frame_rect)

        font = pygame.font.Font("SimHei.ttf", 10)                   # 2
        name_text = font.render(self.name, True, (150, 150, 150))
        win.blit(name_text, (self.x + round(self.frame_width/2) - round(name_text.get_width()/2), self.y - name_text.get_height()))
        
    ...

代码解释如下:

1. name变量用来保存玩家名称,uuid用来防止名称相同的情况(当然uuid很长,拿来作为名称显示不合理,这里重点是不想让玩家名称重复)。

2. 之前是将id值显示到窗口上,现在改为显示name值。

运行结果如下:

 断线重连后,玩家名称不会改变。

5.4 完整代码下载地址

链接:https://pan.baidu.com/s/1aq3-0HWPbNwvCoFgPYpYEg  

密码:q15r

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/107958.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis - Redis持久化:AOF和RDB

1. 为什么要持久化 Redis是内从数据库&#xff0c;宕机后数据会丢失&#xff1b;Redis重启后&#xff0c;为了快速恢复数据&#xff0c;提供了持久化机制&#xff1b;Redis有两种持久化方式&#xff1a;RDB和AOF&#xff0c;这也是Redis无畏宕机与快速恢复数据的杀手锏。 注意…

全球代表供应商!腾讯安全NDR再获Gartner认可

近日&#xff0c;国际研究机构Gartner发布了2022年《Market Guide for Network Detection and Response》&#xff08;《网络检测和响应&#xff08;NDR&#xff09;市场指南》&#xff09;&#xff08;以下简称《报告》&#xff09;&#xff0c;腾讯安全被Gartner列为全球NDR市…

非零基础自学Golang 第17章 HTTP编程(上) 17.3 爬虫框架gocolly 17.3.1 gocolly简介

非零基础自学Golang 文章目录非零基础自学Golang第17章 HTTP编程(上)17.3 爬虫框架gocolly17.3.1 gocolly简介第17章 HTTP编程(上) 17.3 爬虫框架gocolly 我们在之前学习了如何使用标准库实现HTTP爬虫【其实也不算&#xff0c;就实现了简单的请求&#xff0c;但是爬虫不就是这…

别乱用了,用新的。Go SliceHeader 和 StringHeader 将会被废弃!

大家好&#xff0c;我是煎鱼。Go 语言中有个很经典的 (Slice|String)Header&#xff0c;经常出现在大家视野中&#xff0c;为此我写了《Go SliceHeader 和 StringHeader&#xff0c;你知道吗&#xff1f;》给大家介绍&#xff0c;避免被面试官卷到。以重点来讲&#xff0c;Slic…

Alibaba送给开发人员的“礼物”:Java架构成长笔记,深入内核,拒绝蒙圈

提起阿里&#xff0c;行外人联想到的关键词无非是“交易”、“淘宝”、“支付宝”&#xff0c;但对于程序员来说&#xff0c;阿里庞大的技术体系才是最吸引人的。实际上阿里作为国内一线互联网公司的头把交椅&#xff0c;内部的技术体系和发展都是备受关注的&#xff0c;对于程…

【javaScript总结归纳】字符串常用方法总结

前言 在js中我们对字符串进行一部分截取&#xff0c;可以使用slice()函数截取&#xff0c;也可以直接用substring()函数来截取&#xff0c;但是截取也有可能出bug const str小&#x20bb7;和小&#x27a01;今天吃了50块钱的KFC console.log(str.slice(0,5)); 可以在控制台看…

评估EtherCAT从站节点解决方案

本系列博客文章的第1部分介绍了用于C2000™微控制器的EtherCAT从站堆栈解决方案的市场机遇&#xff0c;以及从站堆栈开发快速入门的三个阶段指南。第2部分详细说明了TIC2000 MCU EtherCAT实施的特点和优势。第3部分分别介绍了使用EtherCAT从站和C2000 Delfino MCU controlCARD套…

Linux【windows使用xshell连接本地虚拟机】【Mac使用terminal连接本地虚拟机】

文章目录对于本地虚拟机的配置使用Mac的terminal的ssh连接本地虚拟机windows使用xshell连接本地虚拟机对于本地虚拟机的配置 IP地址和子网掩码。 在虚拟机中使用ping命令判断虚拟机到宿主机是否是连通的。&#xff08;不通的话&#xff0c;关闭Windows防火墙&#xff0c;再试一…

python+pyhyper实现识别图片中的车牌号

背景 最近领导给布置了一个基于图片识别车牌号的工具开发任务&#xff0c;然后就去研究实现逻辑&#xff0c;自己根据opencv写了一个小demo&#xff0c;发现不仅速度慢而且成功率极低。然后&#xff0c;就找到了Hyperlpr开源项目。 环境搭建 排雷1&#xff1a;有教程说在git…

动态内存管理易错点+分析例题

复习一下&#xff1a; 常见的错误&#xff1a; 1.可能返回的是空指针 2.对动态开辟的内存越界访问 3.非动态开辟内存却用free释放 4.使用free释放动态开辟内存的一部分 5.free多次释放 如果加了pNULL的话 free&#xff08;p&#xff09;相当于啥也不干 程序起码不会崩掉 6.动…

RabbitMQ、RocketMQ、Kafka延迟队列实现

延迟队列在实际项目中有非常多的应用场景&#xff0c;最常见的比如订单未支付&#xff0c;超时取消订单&#xff0c;在创建订单的时候发送一条延迟消息&#xff0c;达到延迟时间之后消费者收到消息&#xff0c;如果订单没有支付的话&#xff0c;那么就取消订单。 那么&#xf…

Proteus8仿真:51单片机IrLink红外发送加接受模块的使用

51单片机IrLink红外的使用元器件原理图部分代码单片机1发送main.c单片机2接受main.c工程文件元器件 元器件名称51单片机AT89C51红外收发IRLINK按键BUTTON发光二极管LED-RED时钟激励源DCLOCK与门74LS08示波器 原理图部分 关于IRLINK的使用&#xff1a; 在Proteus上就是一个红外…

数据中台选型前必读(七):解读数据服务的四大关键技术

在前面的文章中&#xff0c;我们介绍了“数据服务”对于“数据中台”的重要性&#xff0c;并讲解了数据服务解决的问题及其核心功能&#xff0c;在这个系列的最终篇我们展开聊聊数据服务的四大关键技术&#xff0c;然后总结一下数据服务架构的三大关键点&#xff0c;希望对大家…

JSP ssh培训管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 JSP ssh 培训管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Mye…

校园打架行为识别检测 yolov7

校园打架行为识别检测系统基于python基于yolov7深度学习框架边缘分析技术&#xff0c;自动对校园、广场等区域进行实时监测&#xff0c;当监测到有人打架斗殴时&#xff0c;系统立即抓拍存档语音提醒&#xff0c;并将打架行为回传给学校后台&#xff0c;提醒及时处理打架情况。…

Word控件Spire.Doc 【超链接】教程(7):在 C#、VB.NET 中的 Word 中创建图像超链接

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

你一定要会的JavaFile

File对象就表示一个路径&#xff0c;可以是文件的路径&#xff0c;也可以是文件夹的路径这个路径可以是存在的&#xff0c;也允许是不存在的File的构造 方法名称说明public File(String pathname)根据文件路径创建文件对象public File(String parent,String child)根据父路径名…

第4章 角色Api控件器的实现与调试

1 自定义管道中间件 1.1 WebApi.Middleware.CorsMiddleware namespace WebApi.Middleware { /// <summary> /// 【跨域访问中间件--类】 /// <remarks> /// 摘要&#xff1a; /// 该管道中间件类主要为了解决在由vue/uni-app前端项目(Cors)访问当前后端项…

你的期待薪资是多少?为什么?

很多人去面试的时候&#xff0c;就像打游戏&#xff0c;过五关斩六将&#xff0c;终于到最后一关了&#xff0c;但是谈薪资的难度堪比打游戏中搞定终级 boss 的难度&#xff0c;真的是太「南」了&#xff0c;好多人都是因为这个问题让自己五味杂陈呀。报高了怕好 offer 失之交臂…

【Call for papers】SIGIR-2023(CCF-A/内容检索/2023年1月31日截稿)

The 46th International ACM SIGIR Conference on Research and Development in Information Retrieval will be held from 23-27 July, 2023 in Taipei. 文章目录1.会议信息2.时间节点3.论文主题1.会议信息 会议介绍&#xff1a; SIGIR是展示新研究成果和展示信息检索新系统和…