🚙

💨 💨 💨

×

  • Categories

  • Archives

  • Tags

  • About

多人快节奏游戏一之C/S游戏架构

Posted on 07-16-2016 | In GS

原文出处

Fast-Paced Multiplayer (Part I): Client-Server Game Architecture


Introduction

This is the first in a series of articles exploring the techniques and algorithms that make fast-paced multiplayer games possible. If you’re familiar with the concepts behind multiplayer games, you can safely skip to the next article – what follows is an introductory discussion.


Developing any kind of game is itself challenging; multiplayer games, however, add a completely new set of problems to be dealt with. Interestingly enough, the core problems are human nature and physics!


The problem of cheating


It all starts with cheating.


As a game developer, you usually don’t care whether a player cheats in your single-player game – his actions don’t affect anyone but him. A cheating player may not experience the game exactly as you planned, but since it’s their game, they have the right to play it in any way they please.


Multiplayer games are different, though. In any competitive game, a cheating player isn’t just making the experience better for himself, he’s also making the experience worse for the other players. As the developer, you probably want to avoid that, since it tends to drive players away from your game.


There are many things that can be done to prevent cheating, but the most important one (and probably the only really meaningful one) is simple : don’t trust the player. Always assume the worst – that players will try to cheat.


Authoritative servers and dumb clients


This leads to a seemingly simple solution – you make everything in your game happen in a central server under your control, and make the clients just privileged spectators of the game. In other words, your game client sends inputs (key presses, commands) to the server, the server runs the game, and you send the results back to the clients. This is usually called using an authoritative server, because the one and only authority regarding everything that happens in the world is the server.


Of course, your server can be exploited for vulnerabilities, but that’s out of the scope of this series of articles. Using an authoritative server does prevent a wide range of hacks, though. For example, you don’t trust the client with the health of the player; a hacked client can modify its local copy of that value and tell the player it has 10000% health, but the server knows it only has 10% – when the player is attacked it will die, regardless of what a hacked client may think.


You also don’t trust the player with its position in the world. If you did, a hacked client would tell the server “I’m at (10,10)” and a second later “I’m at (20,10)”, possibly going through a wall or moving faster than the other players. Instead, the server knows the player is at (10,10), the client tells the server “I want to move one square to the right”, the server updates its internal state with the new player position at (11,10), and then replies to the player “You’re at (11, 10)”:



Effect of network delays.
Effect of network delays.


In summary: the game state is managed by the server alone. Clients send their actions to the server. The server updates the game state periodically, and then sends the new game state back to clients, who just render it on the screen.


Dealing with networks


The dumb client scheme works fine for slow turn based games, for example strategy games or poker. It would also work in a LAN setting, where communications are, for all practical purposes, instantaneous. But this breaks down when used for a fast-paced game over a network such as the internet.


Let’s talk physics. Suppose you’re in San Francisco, connected to a server in the NY. That’s approximately 4,000 km, or 2,500 miles (that’s roughly the distance between Lisbon and Moscow). Nothing can travel faster than light, not even bytes on the Internet (which at the lower level are pulses of light, electrons in a cable, or electromagnetic waves). Light travels at approximately 300,000 km/s, so it takes 13 ms to travel 4,000 km.


This may sound quite fast, but it’s actually a very optimistic setup – it assumes data travels at the speed of light in a straight path, with is most likely not the case. In real life, data goes through a series of jumps (called hops in networking terminology) from router to router, most of which aren’t done at lightspeed; routers themselve introduce a bit of delay, since packets must be copied, inspected, and rerouted.


For the sake of the argument, let’s assume data takes 50 ms from client to server. This is close to a best-case scenario – what happens if you’re in NY connected to a server in Tokyo? What if there’s network congestion for some reason? Delays of 100, 200, even 500 ms are not unheard of.


Back to our example, your client sends some input to the server (“I pressed the right arrow”). The server gets it 50 ms later. Let’s say the server processes the request and sends back the updated state immediately. Your client gets the new game state (“You’re now at (1, 0)”) 50 ms later.


From your point of view, what happened is that you pressed the right arrow but nothing happened for a tenth of a second; then your character finally moved one square to the right. This perceived lag between your inputs and its consequences may not sound like much, but it’s noticeable – and of course, a lag of half a second isn’t just noticeable, it actually makes the game unplayable.


Summary


Networked multiplayer games are incredibly fun, but introduce a whole new class of challenges. The authoritative server architecture is pretty good at stopping most cheats, but a straightforward implementation may make games quite unresponsive to the player.


In the following articles, we’ll explore how can we build a system based on an authoritative server, while minimizing the delay experienced by the players, to the point of making it almost indistinguishable from local or single player games.

游戏服务端常用架构三

Posted on 07-11-2016 | In GS

休闲游戏服务器

休闲游戏同战网服务器类似,都是全区架构,不同的是有房间服务器,还有具体的游戏服务器,游戏主体不再以玩家 P2P进行,而是连接到专门的游戏服务器处理:

和战网一样的全区架构,用户数据不能象分区的 RPG那样一次性load到内存,然后在内存里面直接修改。全区架构下,为了应对一个用户同时玩几个游戏,用户数据需要区分基本数据和不同的游戏数据,而游戏数据又需要区分积分数据、和文档数据。胜平负之类的积分可以直接提交增量修改,而更为普遍的文档类数据则需要提供读写令牌,写令牌只有一块,读令牌有很多块。同帐号同一个游戏同时在两台电脑上玩时,最先开始的那个游戏获得写令牌,可以操作任意的用户数据。而后开始的那个游戏除了可以提交胜平负积分的增量改变外,对用户数据采用只读的方式,保证游戏能运行下去,但是会提示用户,游戏数据锁定。

. . .

游戏服务端常用架构二

Posted on 07-11-2016 | In GS

第三代游戏服务器 2007

从魔兽世界开始无缝世界地图已经深入人心,比较以往游戏玩家走个几步还需要切换场景,每次切换就要等待 LOADING个几十秒是一件十分破坏游戏体验的事情。于是对于 2005年以后的大型 MMORPG来说,无缝地图已成为一个标准配置。比较以往按照地图来切割游戏而言,无缝世界并不存在一块地图上面的人有且只由一台服务器处理了:

每台 Node服务器用来管理一块地图区域,由 NodeMaster(NM)来为他们提供总体管理。更高层次的 World则提供大陆级别的管理服务。这里省略若干细节服务器,比如传统数据库前端,登录服务器,日志和监控等,统统用 ADMIN概括。在这样的结构下,玩家从一块区域走向另外一块区域需要简单处理一下:

玩家1完全由节点A控制,玩家3完全由节点B控制。而处在两个节点边缘的2号玩家,则同时由A和B提供服务。玩家2从A移动到B的过程中,会同时向A请求左边的情况,并向B请求右边的情况。但是此时玩家2还是属于A管理。直到玩家2彻底离开AB边界很远,才彻底交由B管理。按照这样的逻辑将世界地图分割为一块一块的区域,交由不同的 Node去管理。

对于一个 Node所负责的区域,地理上没必要连接在一起,比如大陆的四周边缘部分和高山部分的区块人比较少,可以统一交给一个Node去管理,而这些区块在地理上并没有联系在一起的必要性。一个 Node到底管理哪些区块,可以根据游戏实时运行的负载情况,定时维护的时候进行更改 NodeMaster 上面的配置。

于是碰到第一个问题是很多 Node服务器需要和玩家进行通信,需要问管理服务器特定UID为多少的玩家到底在哪台 Gate上,以前按场景切割的服务器这个问题不大,问了一次以后就可以缓存起来了,但是现在服务器种类增加不少,玩家又会飘来飘去,按UID查找玩家比较麻烦;另外一方面 GATE需要动态根据坐标计算和哪些 Node通信,导致逻辑越来越厚,于是把:“用户对象”从负责连接管理的 GATE中切割出来势在必行于是有了下面的模型:

. . .

游戏服务端常用架构一

Posted on 07-11-2016 | In GS

卡牌、跑酷等弱交互服务端

卡牌跑酷类因为交互弱,玩家和玩家之间不需要实时面对面PK,打一下对方的离线数据,计算下排行榜,买卖下道具即可,所以实现往往使用简单的 HTTP服务器:

登录时可以使用非对称加密(RSA, DH),服务器根据客户端uid,当前时间戳还有服务端私钥,计算哈希得到的加密 key 并发送给客户端。之后双方都用 HTTP通信,并用那个key进行RC4加密。客户端收到key和时间戳后保存在内存,用于之后通信,服务端不需要保存 key,因为每次都可以根据客户端传上来的 uid 和时间戳以及服务端自己的私钥计算得到。用模仿 TLS的行为,来保证多次 HTTP请求间的客户端身份,并通过时间戳保证同一人两次登录密钥不同。

每局开始时,访问一下,请求一下关卡数据,玩完了又提交一下,验算一下是否合法,获得什么奖励,数据库用单台 MySQL或者 MongoDB即可,后端的 Redis做缓存(可选)。如果要实现通知,那么让客户端定时15秒轮询一下服务器,如果有消息就取下来,如果没消息可以逐步放长轮询时间,比如30秒;如果有消息,就缩短轮询时间到10秒,5秒,即便两人聊天,延迟也能自适应。

此类服务器用来实现一款三国类策略或者卡牌及酷跑的游戏已经绰绰有余,这类游戏因为逻辑简单,玩家之间交互不强,使用 HTTP来开发的话,开发速度快,调试只需要一个浏览器就可以把逻辑调试清楚了。

第一代游戏服务器 1978

1978年,英国著名的财经学校University of Essex的学生 Roy Trubshaw编写了世界上第一个MUD程序《MUD1》,在University of Essex于1980年接入 ARPANET之后加入了不少外部的玩家,甚至包括国外的玩家。《MUD1》程序的源代码在 ARPANET共享之后出现了众多的改编版本,至此MUD才在全世界广泛流行起来。不断完善的 MUD1的基础上产生了开源的 MudOS(1991),成为众多网游的鼻祖:

MUDOS采用 C语言开发,因为玩家和玩家之间有比较强的交互(聊天,交易,PK),MUDOS使用单线程无阻塞套接字来服务所有玩家,所有玩家的请求都发到同一个线程去处理,主线程每隔1秒钟更新一次所有对象(网络收发,更新对象状态机,处理超时,刷新地图,刷新NPC)。

. . .

阅读开源服务器源码基础

Posted on 07-04-2016 | In Linux

当阅读一些开源服务器源码的时候, 如果不知道以下知识, 就会有知识盲点, 导致不知所云.
这篇博客会讲述一些相关的编程知识点, 把之前的笔记总结一下.
还是那句老话, 带着问题阅读是最容易让人类迅速进入状态的.

进程的内存布局是什么样的?

记忆口诀 : 文初堆栈

这里写图片描述

每个进程所分配的内存由很多部分组成,通常称之为“段( segment)”。如下所示。

  • 文本段
    包含了进程运行的程序机器语言指令。文本段具有只读属性,以防止进程通过错
    误指针意外修改自身指令。因为多个进程可同时运行同一程序,所以又将文本段设为可
    共享,这样,一份程序代码的拷贝可以映射到所有这些进程的虚拟地址空间中。
  • 初始化数据段
    包含显式初始化的全局变量和静态变量。当程序加载到内存时,从可执
    行文件中读取这些变量的值。
  • 未初始化数据段
    包含了未进行显式初始化的全局变量和静态变量。程序启动之前,系统
    将本段内所有内存初始化为0。出于历史原因,此段常被称为BSS段,这源于老版本的
    汇编语言助记符“block started by symbol”o将经过初始化的全局变量和静态变量与未经
    初始化的全局变量和静态变量分开存放,其主要原因在于程序在磁盘上存储时,没有必
    要为未经初始化的变量分配存储空间。相反,可执行文件只需记录未初始化数据段的位
    置及所需大小,直到运行时再由程序加载器来分配这一空间。
  • 堆(heap)
    是可在运行时(为变量)动态进行内存分配的一块区域盛顶端称作program break。
  • 栈( stack)
    是一个动态增长和收缩的段,由栈帧(stack frames)组成。系统会为每个
    当前调用的函数分配一个栈帧。栈帧中存倍了函数的局部变量(所谓自动变量)、实
    参和返回值。

线程的同步机制有哪些?

  • 互斥量
  • 条件变量
  • 自旋锁
    自旋锤与互斥量类似,但它不是通过休眠使进程阻塞,而是在获取镪之前一直处于忙等(自
    旋)阻塞状态.自旋锁可用于“下情况锁被持有的时间短,而且线程并不希望在重新调度上花
    费太多的成本。
  • 读写锁(也叫做共享互斥锁)
    读写锁也叫做共享互斥锁( shared-exclusive lock)。当读写锁是读模式锁住时,就可以说成是
    以共享模式锁住的。当它是写模式锁住的时候,就可以说成是以互斥模式锁住的。

. . .

MongoDB能取代MySQL或者Redis能取代memcached么

Posted on 06-30-2016 | In DB

mongodb和memcached不是一个范畴内的东西。

mongodb是文档型的非关系型数据库,其优势在于查询功能比较强大,能存储海量数据。

mongodb和memcached不存在谁替换谁的问题。和memcached更为接近的是redis。

它们都是内存型数据库,数据保存在内存中,通过tcp直接存取,优势是速度快,并发高,缺点是数据> 类型有限,查询功能不强,一般用作缓存。

一般现在的项目中,用redis来替代memcached。

. . .

NAT穿越基础

Posted on 06-21-2016 | In Misc
  1. NAT类型
    1. 锥NAT
    2. 对称NAT
  2. NAT作用
  3. 穿透锥NAT
    1. 网络拓扑结构
    2. 使用UDP穿透NAT
    3. 使用TCP穿透NAT
  4. 穿透对称NAT
    1. 同时开放TCP( Simultaneous TCP open )策略
    2. UDP端口猜测策略
  5. 问题总结
  6. 参考

NAT类型

注 : 我们本文主要讨论穿越锥NAT

锥NAT

  • 全锥NAT :全锥NAT 把所有来自相同内部IP 地址和端口的请求映射到相同的外部IP 地址和端口。任何一个外部主机均可通过该映射发送数据包到该内部主机。
  • 限制性锥NAT :限制性锥NAT 把所有来自相同内部IP 地址和端口的请求映射到相同的外部IP 地址和端口。但是, 和全锥NAT 不同的是:只有当内部主机先给外部主机发送数据包, 该外部主机才能向该内部主机发送数据包。
  • 端口限制性锥NAT :端口限制性锥NAT 与限制性锥NAT 类似, 只是多了端口号的限制, 即只有内部主机先向外部地址:端口号对发送数据包, 该外部主机才能使用特定的端口号向内部主机发送数据包。

对称NAT

对称NAT 与上述3 种类型都不同, 不管是全锥NAT ,限制性锥NAT 还是端口限制性锥NAT ,它们都属于锥NAT (Cone NAT )。当同一内部主机使用相同的端口与不同地址的外部主机进行通信时, 对称NAT 会重新建立一个Session ,为这个Session 分配不同的端口号,或许还会改变IP 地址。

. . .

MySQL进阶二

Posted on 06-16-2016 | In DB

事务

MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!

  • 在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
  • 事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。
  • 事务用来管理 insert,update,delete 语句

. . .

1…15161718192021222324252627282930313233343536
Mike

Mike

🚙 🚗 💨 💨 If you want to create a blog like this, just follow my open-source project, "hexo-theme-neo", click the GitHub button below and check it out ^_^ . It is recommended to use Chrome, Safari, or Edge to read this blog since this blog was developed on Edge (Chromium kernel version) and tested on Safari.

11 categories
287 posts
110 tags
about
GitHub Spotify
© 2013 - 2025 Mike