“直播”俄罗斯方块
展示图片在项目文件夹里
项目概述:类似于当前火热的直播平台,该项目由一个服务端,两种客户端构成。直播的玩家选择直播客户端,输入房间号,在本机运行俄罗斯方块游戏。观看直播的人登录观战客户端,输入想看的直播房号,进入可以实时观看到“主播”的游戏实况。还具有聊天室功能。
代码地址:https://github.com/zzaiyuyu/tetris-net/
使用说明:
./server 8080
./client 127.0.0.1 8080
./viewer 127.0.0.1 8080
项目总共分为三个模块
- 玩家客户端
- 观战客户端
- 服务器客户端
核心流程
- 服务器在某个地址上监听
- 玩家客户端和服务器建立TCP连接,输入房间号创建直播间,开始游戏
- 观战客户端建立连接,输入房间号进入直播间,开始观战或聊天
玩家客户端
MVC的设计思想
model部分
每一个图形用一个5X5数组表示,有图案则置为1,无则0.这样总共可以把全部的7类图形用一个结构体数组描述出来。
同时游戏还需要当前正在下落的图案的坐标。
control部分
主流程:
主控制逻辑设置一个定时器,并且捕捉ALRM信号,每过一定时间就自动下落一格。
下落过程中需要判断下一个位置是不是可以走,如果可以走,就擦出当前图案,在下一个位置画出来,如果不能走,就是碰到物体了,需要检测是不是该消除,游戏结束,之后就要开始下一个块了。
其中在判断下一步是否可行时,需要当前整个图案信息才能判断是否碰到物体了,所以在每一次碰到物体首先要保存当前的整体背景。
如何控制方向?
在主控流程加一个死循环,不断的判断是否有按键产生。判断按键首先要设置终端模式,标准输入是键盘输入到内核缓存,输入回车后才进入程序地址空间,将其改为键盘输入直接进入应用程序。然后非阻塞的读取输入程序地址的输入缓存区。
终端属性
假如按了左键,首先判断下一个位置可行不可行,若是非法操作,则恢复上一个图案。假如按上键,利用旋转函数对当前图案进行旋转。
旋转算法
如何设置不同颜色块,显示下一个形状?
在定时下落的函数里,如果碰到不能走的情况,说明要出下一个块了,此时设置一个随机数,造成不同颜色块的效果。同理只需要一个临时变量nextBuf即可记录下一个形状。
view部分
VT100 实现终端画布式打印
观战客户端
观战客户端也遵循经典流程,构造请求,序列化,发送请求,等待响应,解析响应。
建立连接后首先发送请求加入直播间的消息,若服务器端关闭连接则客户端也关闭,证明房间不存在。
之后用poll调用同时监听标准输入和建立好的TCP套接字,若有标准输入则序列化发送给服务器,若有连接读事件则反序列化显示为游戏画面。
这里采用的是自定义的定长协议,一个结构体里包含了消息类型字段以及数据。
服务器
服务器的经典流程,读取请求,反序列化消息,调用业务逻辑代码,序列化的响应结果,发送。
服务器提前为每一个用户开辟一块内存用来保存数据,socket刚好对应了数组下标。
服务器用epoll多路IO转接,对监听套接字送上来的连接创建套接字后同一做读事件监听。之后按客户端发的消息类型进行区分
1代表请求创建直播间,之后不断监听玩家套接字
2请求加入直播间,之后不断监听读事件向其发送图案信息
3我是图案信息,需要转发给房间内的所有人
4我是聊天信息,需要转发给房间内的所有人
首先利用位图查询房间是否存在,非法情况就关闭连接。
这时再维护一个指针数组,数组下标对应了房间号,通过房间号这个句柄建立房间的观战者队列,转发消息都是操纵这个队列来的。
FAQ
- 网络连接不好的时候怎么办?
如果是客户端网不好的情况,由于采用TCP协议,TCP报文的序号保证了有序性,延迟过后瞬间从TCP接收缓冲区拿走很多数据,结果就是屏幕上有快进的效果。
连接超时和超时重传问题都由TCP协议接管,我可以不做考虑。
服务器网不好的情况,开始使用的是阻塞套接字,在read读取数据有可能部分数据来了,触发了epoll_wait, 然后read返回的实际字节数小于想要读取的,这时没做处理的话下次下半截数据到来的时候就会有粘包问题。
之后改为非阻塞,并且使用recv的peek方法解决。
并且在发送大量数据时有可能写失败,先尝试写一次,查看实际放入缓冲区字节够不够,write返回实际写入缓冲区的字节数,不够就设置关心发送缓冲区的写事件,并且在写事件里再判断。
(必须是非阻塞的socket)