坦克大战本为书本《C++项目开发实战入门》中的一个基于MFC实现的单机游戏。因为个人兴趣便将其中的双人游戏改为网络双人对战。
服务器是使用C++实现,实际上写了两个版本,主要为通信协议不同,一个为TCP协议另一个为UDP协议,客户端对应也改了两个版本,但因为UDP协议的版本最后完成的,所以客户端的UDP版更完善。本文也以UDP版本为基准进行讨论。
数据库使用MySQL,主要用于登录时候账号密码的验证。储存信息并不多,信息为用户UID,用户账号以及用户密码。

数据传输使用Protobuf 3。
其中 游戏对战中使用的类结构

//For UDP_Server
syntax="proto3";message prome
{  uint64 state=1; //游戏的状态Account account=2;PVP pvp=3;Game game=4;Bullet bullet=5;
}message Account  //登录状态为0
{uint64 uid=1;//用户UIDstring name=2;string password=3;
}message PVP //匹配状态为2,设计用于分别是否断开重连的状态,现只用于请求对战匹配。
{uint64 setout=1;//uint64 relog=2;}
message Game //游戏状态为4
{float tankx=1;//坦克 X轴方向位置float tanky=2;//坦克 Y轴方向位置uint64 dire=3; //坦克的转向,左为1,右为2,上为3,下为4
}message Bullet     //游戏状态为5,state==5表示对战坦克进行开枪动作。
{                   //客户端中子弹是有归属的,比如属于本地player01坦克或属于对战player02坦克,但任何子弹和任何坦克相遇,坦克都会爆炸。float bulletx=1;//为了简化传输信息的大小,不再传输子弹位置的信息。float bullety=2;//当state==5时候,对战player02坦克的位置上发射的子弹是归属于本地player01坦克的。//换句话说,对战player02坦克的子弹是本地player01坦克替它隔空发射的。
}
state= =0,表示请求验证账号密码。
state= =1, 表示账号密码正确
state= =2,表示客户端请求匹配对手。
state= =3客户端进行游戏初始化,传输坦克最初位置。
state= =4 客户端处于游戏阶段,传输坦克位置信息。
state= =5 表示坦克进行开枪动作
state= =6 坦克被击中结束游戏。
state= =7 表示客户端退出,断开连接。

游戏逻辑如下图

服务器本来打算使用多进程,但游戏实在过于简单,服务器只负责简单的密码验证,匹配对手以及处理信息,所以服务器无论采用TCP还是UDP的都是单线程的。其实服务器已经创建了多一个进程,但完全不需要也用不着,只调一个 cout 函数,只当练习一下也没有将服务器优化回单进程。
TCP版本的服务器通信方面采用Linux特有的I/O复用模型-epoll。在epoll中为了避免输入缓冲中有数据就会一直通知该事件(注册到发生变化额文件描述符),造成重复多次向客户端发送相同数据,可能造成游戏操作延迟。所以epoll默认的将以条件触发的事件注册方式更改为以边缘触发的方式调用。同时边缘触发方式下,以阻塞方式工作的read&write函数有可能引起服务器的长时间停顿。因此,将套接字改为非阻塞模式。
客户端是根据玩家操作发送包的,一个动作发送一次包,但由于动作过于高频,丢包重传会导致延迟的发生,而且会越来越大。为了解决延迟问题重新写了 一个UDP版本。
而在服务器匹配方面,当state==2时,会查询游戏数组匹配对手。所谓的游戏数组是一个结构体数组,结构体里面包含这用户UID,用户IP地址,游戏状态以及对战对手的数组下标。结构体如下:

//For UDP_Server
struct PVP_array{int oneuid;//用户uidint oppo;//对战对手的数组下标struct sockaddr_in one_adr;//用户IP地址int pstate;//游戏状态};
pstate==0 时,表示该结构体为空,可充填用户信息。
pstate==1 时,表示该结构体以充填用户信息。
pstate==2 时,表示该结构体用户正在匹配对战对手。
pstate==3时,表示该结构体用户匹配对战对手完成,此时对战对手数组下标会赋值于结构体中的oppo。

因为用户信息并不多所以使用结构体存储用户的信息,如果用户信息比较多使用类实现会更好。TCP版本的结构体更为简单,因为长连接原因所以直接使用套接字描述符作为不同用户匹配,对战时的唯一标识,连UID都不使用,这时用户账号密码的意义只是登录的钥匙而已没有其它用处,比如用相同账号密码登陆的两个用户可以进行登录对战。而在UDP版本结构体中增加了UID解决了这一个问题,同时使用UID作为用户的唯一标识。
客户端上耗了最多时间。为了能修改客户端,大部分时间都是在读代码。简单熟悉了下MFC给客户端加上了登录界面,也添加了用于通信的类。本来坦克大战游戏中是有迷宫地图的,地图是每次游戏是随机生成的,但是已经不调用随机生成地图的函数了,这样两个客户端联网进行游戏时,可以省略加载统一地图的步骤。坦克原本是按上方向键前进,下方向键后退,左方向键左转,右方向键右转这样的操控方式不太符合个人习惯,便更改为与游戏《1999坦克大战》的操作方式一样,按上方向键往上前进,下方向键往下前进,左方向键往左前进,右方向键往右前进。坦克速度,子弹速度以及子弹数量也做了一些修改。在TCP版的客户端中起初是打算在一个线程完成游戏的操作,信息发送以及信息接收的,于是使用了select函数,把select放到子弹检测的循环中,但是需要坦克发射才开始循环,这时候才更新对战对手的信息。找不到select的合适位置,就在游戏初始化的位置多开了一个线程用于接受对战对手的信息。这时候其实不必使用select函数了,但为了方便TCP版本的客户端中还是调用select函数。

演示视频:

MyVideo_1

代码连接:Github坦克大战
UDP_Tank.rar,TCP_Tank.rar两个是编译完成的UDP和TCP客服端。
UDP_Game.h,UDP_Game.cpp是UDP客户端主要的游戏逻辑部分代码,主要改动也在其中。TCP_Game.h,TCP_Game.cpp亦是如此。
message.bp,mysql_data.h,myql_data.cpp以及UDP_main.cpp可在linux环境下编译成UDP服务器的文件。TCP文件同理。

坦克大战的网络对战实现C++(客户端+服务端)相关推荐

  1. TCP/IP网络编程之基于TCP的服务端/客户端(二)

    回声客户端问题 上一章TCP/IP网络编程之基于TCP的服务端/客户端(一)中,我们解释了回声客户端所存在的问题,那么单单是客户端的问题,服务端没有任何问题?是的,服务端没有问题,现在先让我们回顾下服 ...

  2. TCP/IP网络编程之基于TCP的服务端/客户端(一)

    TCP/IP网络编程之基于TCP的服务端/客户端(一) 理解TCP和UDP 根据数据传输方式的不同,基于网络协议的套接字一般分为TCP套接字和UDP套接字.因为TCP套接字是面向连接的,因此又称为基于 ...

  3. ava联网3D坦克大战(网络编程)2020

    .游戏效果 Java网络编程联机3D坦克大战 在这里插入图片描述 在这里插入图片描述 二.游戏涉及知识 服务器端运用了 IO.线程.网络.面向对象.异常 的内容, 客户端使用 unity3d引擎进行开 ...

  4. 二十五、客户端/服务端架构,网络基础

    一.软件开发的架构 我们了解的涉及到两个程序之间通讯的应用大致可以分为两种: 第一种是应用类:qq,微信.网盘,优酷这一类是属于需要安装的桌面应用 第二种是web类:比如百度.知乎.博客园等使用浏览器 ...

  5. Qt学习心得之网络编程简单的局域网聊天服务端建立

    学而不思则罔,思而不学则殆.学习和思考是相辅相成的,通过这几天对网络编程的学习,收获颇丰.接下来我将利用Qt做的一个以TcpIp协议为传输方式的简单的局域网聊天服务端与大家分享下: 首先谈谈我个人对T ...

  6. Linux C++服务器项目——网络编程1 (socket通信,服务端,客户端)

    牛客 C++高并发服务器开发 参考笔记 1.MAC地址 2 IP地址 2.1 简介 2.2 IP地址编址方式 2.3 子网掩码 3 端口 3.1 简介 3.2 端口类型 4 网络模型 4.1 OSI七 ...

  7. C/C++网络编程工作笔记0003---客户服务端程序说明

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 在UNIX中,一切都是文件,0代表输入,1代表输出,2表示错误 简单来说,当您打开文件时,操作系统 ...

  8. 【网络编程】TCP/IP (客户端--服务端)

    数据链路层: 通过各种控制协议,将有差错的物理信道变为无差错的.能 可靠传输数据帧的数据链路. MAC(物理地址)48位 网络层: 实现数据包的选路和转发. IP 地址有分 IPV4 (32位)和 I ...

  9. (unix网络编程)即时通讯工具二:服务端与客户端融合

    本文的聊天工具,理论上来说是没有具体区分服务端和客户端的(只针对此处的点对点聊天工具,例如QQ,微信这种IM工具是有服务器端的,要不然咋会出现服务器登不上去的故障呢?),另外服务端和客户端除了sock ...

  10. java坦克大战登录界面设计_基于JAVA的坦克大战设计和实现-代码.doc

    JISHOU UNIVERSITY 本科生毕业设计 题 目:基于JAVA的坦克大战设计与实现作 者:学 号:所属学院:专业年级:指导教师:职 称:完成时间:2012年5月7日 吉首大学 基于JAVA的 ...

最新文章

  1. linux挂载分区至目录
  2. SVN钩子hooks使用
  3. Scrapy 1.4 文档 01 初窥 Scrapy
  4. [转] 测试员,敢问路在何方(来自微软工程师)
  5. lombok链式调用_翻车!记一次使用 Lombok 造成的事故!
  6. vue.js 事件的案例以及 v-model 的学习
  7. 高等数学-第一章 函数 极限 连续
  8. AJAX培训第二讲:使用AJAX框架(下)
  9. 华为校园招聘面试题目及流程
  10. class CText{}; CText t; int const CText::*p; 什么意思?
  11. 我想请教一下我这个错误的原因以及怎么解决,求各位大佬帮忙,感激不尽。
  12. ubuntu18.04(Jetson)以及火狐浏览器设置终端代理和清除代理命令
  13. C++入门:让计算机“开口说话”
  14. VUE中根据文件后缀名显示对应的图标
  15. 群友转发了一段家庭矛盾的视频
  16. 软件测试的正向思维,反向思维
  17. 国开本科计算机应用基础操作题,新版国家开放大学中央电大本科计算机应用基础操作题题库...
  18. 获取token(/oauth/token)
  19. 如何写一手好文章:练习、技巧,以及艺术
  20. 从前有座灵剑山--与邪教辩论(1)

热门文章

  1. 增值电信许可证与icp许可证有什么区别
  2. 余淼杰老师 经济学原理复习笔记(宏观3) 2020-12-14
  3. String类练习:我国的居民身份证号码,由由十七位数字本体码和一位数字校验码组成。
  4. Java全栈开发---Java ERP系统开发:商业ERP(十二)数据的导入导出(Excel)
  5. 泛微OA流程表单提交JS验证
  6. excel打开很慢_Excel打开很慢的解决方法
  7. 冬瓜哥对时间和空间的理解方式—时空参悟(上)
  8. Javascript中Promise对象
  9. 计算方法复习提纲-中
  10. python tkinter 窗口最大化