程序作品(2)——坦克动荡(联机版)(重制版)
2023-06-18 00:57:57 哔哩哔哩

筹划


【资料图】

阅读过我之前的文章的读者们都知道,坦克动荡是一款刺激的双人射击游戏。为了提升游戏体验,我在去年制作了该游戏的联机版本。但是这个联机版本有许多问题,包括但不限于只能在同一局域网下联机、代码可读性和可维护性差、运行效率低下等等。因此,经过了一年的技术积累,我决定重新写一遍这个游戏,顺便修复一下上面提到的那些问题。

1. 跨局域网连接

使用python的socket库实现跨局域网连接其实非常简单。在局域网内部连接的前提下,只需要把服务器和客户端的

改成

即可

(这么简单的方法我去年在百度上硬是查不到,就无语

1.1 跨局域网连接衍生出的bug

由于跨局域网连接时两台电脑处于不同的局域网下,因此信息传输就需要经过许多路由器和交换机。为了减轻这些交换机的压力,一台电脑所发送的多条信息有可能被打包成一个数据包一起发送,而很长的信息也有可能被切成多个数据包分开发送。

这样在接受信息的时候,就有可能出现执行一次接受命令就接收到对方发送的多条信息,或者一次接受命令不能完整接受一条信息的情况。这就是粘包问题

我在当时还不知道粘包问题的存在。因此在调这段代码的时候的心理活动大家可以自行脑补一下

解决粘包问题的方法有很多,我在这里使用的是在消息前面注明消息长度,以便在接受的时候把粘在一起的消息拆分开来的方法。

由于在这个程序里发送的信息都比较短,因此没有出现将一条长信息拆分成多条信息发送的情况。但是在下面一篇文章里即将介绍的另一个项目中,就出现了这种情况。因此这个解决方法在下一个项目中还需要进行一点改变

具体的实现方法是这样的:

在发送端,每生成一个待发送的字符串的时候,都求一下这个字符串的长度,并将这个长度放在字符串的开头

在接收端,首先准备一个列表叫做recv_list。这个列表相当于一个队列,每次需要接收信息的时候都先检查一下这个队列有没有空,如果没有空则先从这个队列里弹出信息来使用,如果空了则执行一下接受命令,并把接收到的信息拆开按顺序放进这个队列里,以便下次取用。

2. 服务器

在进行跨局域网连接的时候,我发现由于某些未知的原因(大概率是因为网关和防火墙的限制),Windows电脑无法作为服务器连接其它电脑,而Mac则有一定概率可以连接。又由于我使用的检测键盘活动的库只能在Windows电脑上使用,因此我就无法像我之前那个联机版那样将客户机用作服务器了。这就意味着我必须单独写一个服务器程序来管理多台客户机的连接。

服务器和客户机之间的通信过程大致和之前那个联机版一样。就是将检测子弹碰撞放在了服务器上,坦克的移动在客户机上完成,并且服务器要负责同步两台客户机之间的信息。这里不过多赘述

服务器这里唯一的难点就是如何让一台服务器同时服务多场比赛。这就需要用到多线程(虽然说我在上一个联机版中将多线程用于与客户机通信,但是我发现那是完全没有必要的,反而会增加编程难度)

这里的多线程的逻辑大致是这样的:

在服务器代码里定义一个函数,把所有游戏开始之后的代码都放进去。主程序负责接受客户机连接,一旦接收到两个客户机的连接,就开一个新的线程来执行游戏函数,并将那两个客户机的连接信息传进去。

但是不同的操作系统对于多线程传递参数的规定是不一样的,像macos和Windows都支持传递socket表示连接信息的变量,但是Linux就只能传递数字和字符串等信息。因此当使用Linux系统作为服务器时,多线程的代码就需要进行一些变化,这些变化在下一个项目中会讲到。

总结

比起上一版的连接程序,这个重制版带来了非常多的改变,包括可以跨局域网连接,可以一台服务器服务多场游戏等等。但是跨局域网连接的时候会受到防火墙和网关的限制,因此没有保证一定会连接成功,因此我不会开放服务器供大家体验。不过这个重制版在同一局域网下也可以使用,因此大家如果想体验的话可以使用自己的电脑作为服务器在同一局域网下与他人游玩。

下期预告:家庭监控系统

注:

我已经将这个项目的源代码上传到百度网盘。点击“阅读原文”即可下载

链接:https://pan.baidu.com/s/1_4maf_6x0PSyErHEt7TIVQ?pwd=zw48 

提取码:zw48

从bilibili网页端复制的文章内容会自动带有作者和出处。请读者在复制链接的时候注意删除读者和出处,否则会提示链接不存在

相关新闻: