元宇宙是一个通过科学技术手段链接和创造的虚拟世界,它与现实世界进行映射和交互,并具有一个新的社会系统的数字生活空间。
元宇宙本质上是现实世界的虚拟化和数字化过程,需要内容生产、经济体系、用户体验和物理世界内容的大量转化。但是,元宇宙的发展是渐进的,有共享的基础设施、标准和协议支撑,最终由众多工具和平台的不断集成和演进而形成。
以上是百度百科的内容。不懂也没关系。总之,宇宙再复杂,也是一个从无到有的过程。那么现在就从最原始最基础的“游戏开发”开始吧。
开发过程的初步规划如下:
1.先开发一款多功能的网络游戏。
2.在游戏中加入区块链虚拟货币系统。
3.开发NFT认证系统,兼容传统游戏。
4.开发虚拟和现实之间的交互界面。
5.接受传统游戏的原生态系统,使之成为超宇宙游戏的一部分。
什么是多功能网游?与传统网游不同的是,它们的功能极其集中,比如虚拟社区、虚拟经济、虚拟商城、虚拟办公室等互联网的新兴形态,都是在各自的领域独立发展。多功能游戏是将许多元素集中在一个系统中。
可能还有很多人不太明白具体的意思。举个例子,以前开发一个游戏,会有一个专用于用户登录的“LoginServer”,一个专用于游戏处理的GameServer,一个专用于游戏公告和用户注册的网站服务器,以及专用于数据访问和传输的数据服务器(SQLServer,MySQLServer)。至于商场社区,动态平衡,服务器集群等。它们不在列表中。
多功能的游戏只能有一个集成功能的服务程序。比如以前开发的网站,可以用ASP、PHP、JSP、ASP.NET等脚本语言开发。但是多游戏服务程序是不能用任何已知的脚本语言开发的,必须自己完成。最终服务器只有一个服务程序,包含了元宇宙游戏所涉及的所有功能,可以自行完成多分区、多线游戏的分发部署。
为什么一定要强调职能的集中化?因为元宇宙是一个全新的宇宙时空,需要虚实结合。比如我们现实生活中的宇宙,所有的物理规律,公理常数等等。一旦定义,就不能更改。然而,许多传统的编程和脚本语言不能跨平台。即使它们可以跨平台,它执行它,你执行你的。元游戏对实时性要求很高。如果仍然使用传统的编程和开发方法,用独立的程序代码来执行,是不可能做到瞬间统一协调的。
但是,目前能够满足元宇宙游戏的基础设施还没有出现。例如,在软件开发中,没有一种编程软件能够满足所有人类程序的应用需求。硬件方面,即使5G全方位覆盖也无法满足超宇宙游戏的带宽需求。
但是不能因为这些缺点就不做了。离真正的元宇宙还很远。我们可以初步开发出比较接近超宇宙的游戏,然后还要不断调试、改进、完善、升级。比如在“大爆炸”的那一刻,我们现在的宇宙产生了一切被称为“道”的东西,比如天命、天理、套路等等。但是在“大爆炸”之前呢?谁知道设计和创造宇宙的“无名”,经过了多少次的修改和重启,才有了我们现在所能认出的精致宇宙。
目前,规划元宇宙正在制定统一的标准协议,但现有的操作系统根本无法“统一标准”。所以元宇宙是一个需要新概念设计的操作系统。我们要等到这些都准备好了,难道不是要等到猴年马月吗?
为什么“他们”说他们想要一个全新概念的操作系统?网上有很多解释,我只从我现在即将面临的一些问题来反映具体情况。比如游戏跨平台时,最基本的文字传输会面临标准不统一的问题。新兴平台大多采用UTF-8标准,但Win系统下的软件只有ANSI和UNICODE标准。如果使用跨平台编程或脚本语言,就必须采用统一的标准。事实上,我们必须考虑到所有的标准,否则我们只能在世界上所有的人类都被统一的操作系统取代时开发元宇宙。
事不宜迟,我们开始工作吧。首先,我们要设计自己的网站服务器,而不是使用传统的脚本语言。不用任何现成的工具,自己动手。在现有的编程系统中,没有关于网站服务器如何写自己的信息。那么我们只能使用最新的编程软件——SEC中文编程来开发,因为它是一个不依赖于任何现有编程语言的框架,可以从零开始构建完全独立、开放、兼容的软件程序。下载z5x.cn/Sec.rar
这个网站服务器并不是基于任何你听说过的脚本语言,所以不要去想怎么写你以前知道的网站代码。所以我们先熟悉一下WebSocket协议,预热一下,清醒一下。提前说一下,我估计这个协议你短时间是看不懂的。今天时间有限,明天开始实践教学。在SEC编程中,WebSocket的网站服务器的开发有十行左右的核心代码,包括包处理、协议分析、SHA1加密、ANSI和UNICODE到UTF-8的相互转换、密文的解密和传输等。我就一一介绍。你只需要复制我提供的代码,直接编译就可以了。
还有王维老师专题科普元宇宙的详细视频。他主要讲的是元宇宙的基本原理和概念性知识,如区块链、SHA256签名加密等相关知识点,但并没有讲实际应用。我可能没有他讲得那么生动,但我每给你一段代码,都会尽力描述它是如何工作的,如何应用的。
通常Web应用的交互方式是客户端向服务器发送HTTP请求,服务器根据客户端的请求返回相应的数据。在这种交互模式下,通信双方是不平等的,因为所有的请求都是由客户端发起的。对于HTTP/1.x协议[RFC 1945],[RFC 2616],协议本身并没有提供服务器主动向客户端推送数据的机制。所以基于HTTP/1.x的Web应用如果需要获取服务器的数据或状态,只能使用长轮询。最典型的例子是持续集成软件Jenkins,在作业构建过程中,需要在浏览器中向用户展示实时控制台输出。如果在构建过程中进入浏览器的开发者模式,可以看到Jenkins周期性的向服务器发送请求,拉取实时的控制台输出数据,比如一些基于web的网络游戏,比如FPS游戏。客户端需要知道当前实时的全局状态,比如其他玩家的当前坐标和装备等。如果使用HTTP/1.x协议,只能使用不断轮询服务器的方法来获取最新的状态数据。一方面,这种方法效率低且不实时,消息的实时性取决于两次轮询之间的间隔。在最坏的情况下,需要晚于一个间隙才能得到最新的数据。另一方面,频繁的轮询也增加了服务器的额外负载。客户端需要维护一个单独的连接来轮询服务器状态。WebSocket协议就是为了解决这个问题。WebSocket协议提供了全双工的通信机制,服务器可以主动向客户端推送数据。WebSocket协议使用HTTP协议握手,使用与HTTP相同的默认端口。这一切都是为了兼容现有的HTTP组件或代理,但是WebSocket和HTTP是独立的协议,它们之间没有层级关系。WebSocket的官方协议文档是[RFC 6455]。本文全面论述了WebSocket协议的设计和工作原理。
1.WebSocket协议概述WebSocket协议主要用于解决基于HTTP/1.x的Web应用无法从服务器主动推送至客户端的问题。为了兼容现有设施,WebSocket协议使用与HTTP协议相同的端口,并使用HTTP升级机制与WebSocket握手。握手完成后,通信双方可以以WebSocket协议的方式进行交互。
WebSocket使用TCP作为传输层协议。类似于HTTP,WebSocket也支持在TCP之上引入TLS层建立加密数据传输通道,即TLS之上的WebSocket,WebSocket URI的WebSocket结构类似于HTTP URI。URI的一般形式是ws://host:port/path/query for web socket over TCP使用端口80,WSS://host:port/path/query for web socket over TLS使用端口443。
在WebSocket协议中,帧是双方数据传输的基本单位。像其他网络协议一样,帧由两部分组成:报头和有效载荷。有许多类型的帧,并且帧的类型由其报头中的操作码字段指示(将在下面讨论)。WebSocket帧可以分为两类,一类是用于传输控制信息(比如通知对方关闭WebSocket连接)的帧,另一类是用于传输应用数据的帧。使用WebSocket协议的双方需要先握手,握手成功后才能开始使用帧传输数据。
2.WebSocket握手当客户端要使用WebSocket协议与服务器进行通信时,首先需要确定服务器是否支持WebSocket协议,所以WebSocket协议的第一步就是握手。WebSocket握手采用HTTP升级机制,客户端可以发送如下结构发起握手(请注意WebSocket握手只允许HTTP GET方法):
GET/Chat HTTP/1.1 host:server . example . com Upgrade:WebSocket Connection:Upgrade Sec-WebSocket-Key:dghlihnhbxbzsbub 25 jzq==Origin:http://example . com Sec-web socket-protocol OL:Chat,Super Chat Sec-web socket-Version:13在HTTP头中设置Upgrade字段,其字段值为web socket,并在连接字段中指明Upgrade。如果服务器支持WebSocket协议并同意握手,则可以返回如下所示的结构:
HTTP/1.1 101交换协议upgrade:WebSocket connection:upgrade Sec-WebSocket-Accept:s 3 plmbitxaq 9 kygzzzhzrbk xOo=Sec-web socket-Protocol:chats EC-WebSo Cket-Version:13下面我们详细讨论一下web socket的握手细节。客户端发起握手时,除了升级之外,还需要设置其他头字段。
| Sec-WebSocket-Key |,必选,由客户端随机生成的16字节值,然后用base64编码。客户端需要确保该值足够随机并且不可预测(换句话说,客户端应该使用具有足够熵的随机数生成器)。在WebSocket协议中,必须传输header字段,如果在客户端发起握手时缺少该字段,则握手| Sec-WebSocket-Version |无法完成。它必须被传递,指示WebSocket协议的版本。RFC 6455的协议版本是13,相应的WebSocket已经在RFC 6455的草案阶段实现。他们当时使用的是较低的版本号。如果客户端同时支持多个版本的WebSocket协议,可以在该字段用逗号分隔支持的版本列表(根据预期程序降序排列),服务器可以选择一个支持的协议版本| Sec-WebSocket-Protocol |。或者,当客户端发起握手时,可以在报头中设置该字段。该字段的值是客户端在与服务器交互时想要使用的一系列子协议。多个子协议由逗号分隔,并按照客户端预期的降序排列。服务器可以根据客户端提供的子协议列表选择一个或多个子协议。可选地,在websocket握手阶段,客户端可以在报头中设置该字段,以指示它想要使用的WebSocket协议。如果扩展服务器支持WebSocket协议,并同意与客户端握手,则应该返回HTTP状态码101,表示同意协议升级,同时设置升级字段,将值设置为WebSocket。并将连接字段的值设置为Upgrade,这与标准的HTTP升级机制完全相同。除此之外,服务器还应该设置与WebSocket相关的头字段:
| Sec-WebSocket-Accept |,必选。当客户端发起握手时,它通过| Sec-WebSocket-Key |字段传递一个由base64编码的随机生成的16字节字符串。如果服务器收到握手,那么值要用WebSocket幻数' 258 eafa 5-E914-47DA-95CA-C5 ab 0 DC 85 b 11 '连接成一个字符串,得到的字符串要用SHA-1散列,得到的散列值要用base64编码,最后的值就是这个字段的值。例如,假设客户端传递的Sec-WebSocket-Key是' dGhlIHNhbXBsZSBub25jZQ=='那么服务器应该首先用WebSocket幻数拼接字符串。得到' dghlihnhxbszsbu 25 jzq==258 eafa 5-e914-47da-95ca-C5 ab 0 DC 85 b 11 '然后对字符串进行SHA-1哈希运算,得到哈希值0x b 30 x7a0x 4f0x 2c0x c 00x 620x 4f0x 160x 900 xf 60 x 460x 060x cf0x 380x 590x 450x B20x be0x c 40 xea,然后对哈希值进行base64编码。Sec-WebSocket-Accept的最终值是S3 pplmbxaq 9 kygzzzhzrbkxoo=。当客户端收到服务器的握手响应时,会做同样的操作,检查值是否符合预期,从而判断服务器是否真的支持WebSocket协议。这个设置步骤的目的是为了最终验证服务器对WebSocket协议的支持,因为对于一些没有正确实现HTTP升级机制,但实际上并不支持WebSocket的Web服务器来说,单纯使用升级机制也可能会返回预期的升级。在引入WebSocket幻数并进行这一系列操作后,很大程度上可以确定服务器确实支持WebSocket协议| Sec-WebSocket-Protocol |。可选地,如果客户端在握手时传递所需的WebSocket子协议,则服务器可以从客户端传递的子协议列表中选择一个支持的子协议。服务器可以不设置该字段来指示它不希望或不支持由客户端传送的任何WebSocket子协议| Sec-WebSocket-Extensions |。它是可选的,类似于Sec-WebSocket-Protocol字段。如果客户端提供了一个扩展列表,服务器可以选择其中一个作为该字段的值。如果服务器不支持或不想使用这些扩展,则不设置字段| Sec-WebSocket-Version |,必须交付该字段。服务器选择由客户端提供的支持的WebSocket协议版本之一。如果服务器不支持客户端交付的所有WebSocket协议版本,服务器应立即终止握手。并返回HTTP 426状态码,同时在头部设置| Sec-WebSocket-Version |字段,指示客户端支持的WebSocket协议版本列表。如果服务器收到客户端的握手,它会根据上述规则向客户端返回握手响应,客户端会检查服务器返回的握手响应。如果校验成功,WebSocket握手就成功了,然后双方就可以开始双向数据传输了。发起握手后,客户端必须处于阻塞状态。换句话说,客户端必须等待服务器发回响应,然后才能开始数据传输。客户端对服务器握手响应的验证机制如下:
客户端应该首先检查服务器返回的状态码是否是101。只有当HTTP状态码为101时,才表示服务器同意协议升级。对于其他类型的状态代码,客户端应该根据HTTP状态代码的语义来处理它们。客户端应该检查服务器返回的响应是否包含升级字段。如果缺少,则表示升级不成功。客户端应该终止websocket握手。客户端要检查升级字段的值是否是WebSocket(这个字段是不区分大小写的,比如websocket,WebSocket,webSocket等。都是合法的)。否则,客户端应终止WebSocket握手。客户端应按照上述方式验证服务器返回的Sec-WebSocket-Accept字段的值是否合法。如果字段不存在或者值不符合预期,那么客户端应该终止WebSocket握手。如果服务器返回的头包含Sec-WebSocket-Extensions,但其字段的值不在客户端最初向服务器发起握手时传递的Sec-WebSocket-Extensions的值列表中,则客户端应该终止WebSocket握手。如果服务器返回的头包含Sec-WebSocket-Protocol,但该字段的值不在客户端最初向服务器发起握手时传递的Sec-WebSocket-Protocol的值列表中,则客户端应该终止WebSocket握手。如果客户端验证服务器的握手响应通过,则WebSocket握手阶段完成,然后双方可以进行WebSocket的双向数据传输。
3.WebSocket数据帧)WebSocket以帧为单位传输数据,帧是客户端和服务器之间数据传输的最小单位。当消息太长时,通信器可以将消息分成多个帧发送。接收方收到后,会再次拼接解码,还原完整的消息。在WebSocket中,有多种类型的框架。帧的类型由帧头中的操作码字段指示。WebSocket框架的结构如下:
该结构的字段语义如下:
FIN,长度为1位。这个标志位用来表示当前帧是消息的最后一段,因为WebSocket支持将一个长消息拆分成几个帧发送。拆分后,除了最后一帧,前一帧的FIN字段为0,最后一帧的FIN字段为1。当然,如果消息没有分段,那么一个帧包含完整的消息。此时其FIN字段的值为1RSV 1 ~ 3。这三个字段是保留的,只能在扩展WebSocket时使用。如果没有启用扩展,这三个字段应该设置为1。如果接收方接收到RSV 1 ~ 3不全为0的帧,且双方没有协商使用WebSocket协议扩展,接收方应立即终止WebSocket连接操作码,该操作码长4位。该字段将指示帧的类型。RFC 6455中定义了几个操作码:0x0,这意味着它当前是延续帧0x1。表示当前帧是文本帧0x2,表示当前帧是二进制帧0x3 ~ 7。目前是保留的,以后会作为更多的非控制类frame0x8使用,也就是说当前帧是一个连接关闭,用来关闭WebSocket连接0x9。目前是ping帧(下面讨论)0xA,目前是pong帧(下面讨论)0xB ~ F,目前是保留的,以后会作为更多的控制类帧使用。
掩码,长度为1位。该字段是一个标志位,用于指示帧的数据(有效载荷)是否被屏蔽。RFC 6455规定,当且仅当客户端发送给服务器的帧需要屏蔽时,Mask主要用于解决代理缓存污染攻击(详见RFC 6455第10.3节)。Payload len表示帧有效负载的长度,以字节为单位。该字段的长度是可变的,可以是7位、716位或764位。具体来说,当有效载荷的实际长度为[0,125]时,有效载荷Len字段的长度为7位,其值直接表示有效载荷的实际长度;当有效载荷的实际长度为126时,有效载荷Len后面的16位将被解释为16位无符号整数,该整数的值表示有效载荷的实际长度;当有效载荷的实际长度为127时,后面的64位将被解释为64位无符号整数。该整数值表示有效载荷屏蔽键的实际长度,这是一个可选字段。当屏蔽标志位为1时,表示这是一个屏蔽帧。此时,屏蔽键字段存在,其长度为32位。RFC 6455规定,所有从客户端发送到服务器的帧都必须覆盖掩码,也就是说,对于所有从客户端发送到服务器的帧,这个字段都必须存在。该字段的值由客户端使用具有足够熵的随机数生成器生成。关于掩膜覆盖,我们将在下面讨论。如果屏蔽标志位为0,则该域的有效载荷将在帧中设置(注意,该域不设置,不只是分配)。该字段的长度是任意的,并且该字段是帧的数据部分。如果通信双方协商使用WebSocket扩展,那么扩展数据也会存储在这里,而扩展数据的应用数据,它们的长度之和就是Payload Len字段指示的值。4.WebSocket掩码算法RFC 6455规定,所有从客户端发送到服务器的WebSocket帧的有效载荷部分都必须覆盖一个掩码。这是为了避免代理缓存污染攻击(更多详细信息,请参见RFC 6455第10.3节)。如果服务器接收到没有掩码覆盖的帧,服务器应该立即终止WebSocket连接。掩码覆盖仅针对帧的有效载荷部分,掩码覆盖不会改变有效载荷的长度。掩膜覆盖的算法如下:
客户端使用随机数生成器随机生成32位屏蔽密钥,该随机数生成器具有足够高的熵来遍历以字节为单位的有效载荷。对于有效载荷的第I个字节,首先执行i MOD 4以获得J,然后掩码覆盖的有效载荷的第I个字节的值是原始有效载荷的第I个字节和Masking-Key的第J个字节。我们使用原始的-octet-i来表示有效载荷在被覆盖之前的第I个字节。transformed-octet-i表示覆盖后有效载荷的第I个字节,masking-key-octet-j表示masking-key的第j个字节,那么上述算法的操作可以用下面两个公式表示:
j=I % 4 transformed-octet-I=original-octet-I xor Masking-key-octet-j服务器收到客户端的帧后,首先检查mask标志位是否为1,如果不是,则应立即终止握手,然后根据Masking-Key字段的值重复上述操作,得到原始净荷数据。
5.WebSocket消息分片当要发送的消息过长或者消息是实时生成的,无法预测具体长度时,客户端可以将消息分片成帧后发送给服务器。分段的另一个考虑是重用底层的TCP连接。当客户端有多个独立的数据要发送时,可以在TCP链路上重用消息分段,并且可以将多个数据段并发发送到服务器。如果读者了解HTTP/2 [RFC 7540]的话,可以知道这也是HTTP/2的做法,但是RFC 6455并没有具体指出如何实现WebSocket碎片消息的并发传输。在HTTP/2中,并发是通过流联系起来的。根据流标识符,接收者可以知道哪些消息在逻辑上是连续的。在WebSocket中,如果不引入额外的机制,服务器在并发传输时无法区分哪些消息段在逻辑上属于同一个消息。需要通过额外的WebSocket扩展机制来实现,这里就不讨论了。下面讨论的碎片化场景都是在没有并发传输的前提下。
消息的分片主要通过使用帧头的FIN和Opcode字段来实现。对于非分片报文,一帧携带一条完整的报文,此时没有后续帧,所以其FIN字段为1,opcode根据报文是文本报文还是二进制报文分别选择0x1或0x2。对于碎片化的消息,我们以短信为例。短信的操作码是0x1。如果不进行分片,则帧的FIN字段为1,操作码字段为0x1。如果进行分段,则第一个分段帧的FIN字段为0,操作码为0x1。但是,从第二个片段到倒数第二个片段,其FIN字段为0,Opcode字段的值为0x0 (0x0表示这是一个延续帧)。对于最后一个片段,其FIN字段为1,Opcode字段的值为0x1。对于片段消息,发送方必须按顺序发送它们。因此,TCP保证传送到上层的数据是有序的,因此接收方也将按照发送方发送的顺序接收消息,并且它可以拼接片段以获得完整的消息。
控制类的帧(如Ping帧、Pong帧,下面会讨论)可以允许插入到分片消息的发送过程中。如果没有的话,碎片化的消息数量会太大,发送时间会很长。控制类的消息需要等到消息发出后才能及时送达对方,从而产生一系列问题(下面会讨论)。
6.WebSocket控件类frame控件类frame主要用来传递一些连接控制信息(比如关闭框架用来关闭WebSocket连接)。RFC 6455定义了三种控制类帧,即关闭帧、Ping帧、Pong帧。
关闭框架关闭框架,顾名思义,是用来关闭WebSocket连接的。当WebSocket连接需要关闭时,通信方发送关闭帧给对方。该帧可以包含有效载荷。如果是,有效载荷前两个字节的16位整数表示对应的误码,然后ASCII编码只是一个错误原因。这个错误原因不需要可读,一般用于调试信息。当使用WebSocket通信的任何一方收到关闭帧时,您应该继续向另一方返回关闭帧。通常情况下,你需要将错误码回显给对方。收到关闭帧后发回给对方,通信方便。你可以认为WebSocket连接已经关闭了。此时,底层TCP连接应该关闭。Ping帧Ping帧作为探测帧,主要用于实现WebSocket层保活,或者检测对方是否还处于可恢复状态。Ping帧可以包含有效负载Pong帧帧。一方面,作为对Ping帧的响应,接收方在接收到Ping帧后应立即将其发送回Pong帧,有效载荷的内容应与Ping帧相同。如果接收方收到多个ping帧,但没有时间回复Pong帧,则只需回复最后一个Ping帧。另一方面,Pong帧可以由通信方发送。作为一种心跳包7。WebSocket Waving RFC 6455将连接关闭表述为关闭握手,我更倾向于表述为Waving以区别于建立连接的握手。WebSocket连接关闭分为关闭和关闭两个阶段。当从另一方发送或接收关闭帧时,WebSocket连接从打开状态变为关闭状态。这个时候可以说浪潮已经开始了。接收到关闭帧后,通信方应立即将关闭帧发送回另一方,并关闭底层TCP连接。此时,WebSocket连接处于关闭状态。
8.WebSocket状态代码不同于HTTP。WebSocket在传输数据时通常使用帧作为传输单位。与HTTP协议不同,每个交互都有一个状态代码。WebSocket本身有一个状态代码,但是它只在关闭框架中使用,以指示连接关闭的原因(它可能是正常关闭的,也可能是因为发生了错误)
RFC 6455定义了几个WebSocket状态代码:
000,表示连接正常关闭,1001,表示通信方已经断开(正在离开)。例如,服务器关闭或客户端关闭网页1002,这意味着通信方由于协议错误而关闭连接。