# 在ET的客户端中，使用网络要用到以下几个组件（不介绍基础设施）。

组件名称| 组件作用
---|---
OpcodeTypeComponent|消息类型加载组件。加载标记了【MessageAttribute】注解的类，作为消息执行的类型，并存储在这个组件的opcodeTypes字段下，提供后续方法使用。
MessageDispatcherComponent|消息分发组件，加载消息处理器。加载所有标记了【MessageHandlerAttribute】属性的类，并提供Handle方法，将传入的MessageInfo发送给指定的消息处理器
NetworkComponent |NetworkComponent是其他上层网络访问组件的基类，这个类型在服务端和客端项目公用。用于 指定该协议、指定构包解析方式、指定消息转发器，开始socket监听、创建session。内部有一个AService字段。抽象了udp和tcp协议的连接工厂，用于创建channel使用tcp做服端的时候可以创建多个Session，每个Session都是一个连接的高层抽象。这个类型在服务端和客户端项目公用。其提供的MessageDispatch和MessagePacker仅在客户端项目使用。一个是客户端消息转发器，一个是客户端消息打包器。
NetOuterComponent |继承自NetworkComponent，用于对外网的连接。可以在Awake中指定协议，指定包解析器。客户端使用的session都是通过这个组件创建的。需要切换网络协议或者数据序列化方式就在这个组件的Awake方法中指定对应的参数就可以了。
SessionComponent    |SessionComponent 组件用于存储Seesion，目前客户端只会存在一个在用的session。登录后获得的GateSession会存储在这个组件中。会在之后的对服务器端的调用中使用这个session。
ClientFrameComponent | 用于处理帧同步。

# 很重要的Session对象的解释
   每个Session都是一个连接的高层抽象。
向session另一端做rpc调用可以调用它的Call方法，发送消息可以调用Send，
二者的区别在于是否需要服务器响应一个反馈消息。
定义消息或者rpc请求的时候使用Message标签设置消息类型与opcode的对应关系。
session是由NetworkComponent创建的，参数是 NetworkComponent的本类实例 + 用于收发字节码的AChannel实例。这个AChannel则是由NetworkComponent中的AService工厂创建的。

## 流程：
    1创建session后（调用构造函数），session开始StartRecv()方法，这个方法循环通过异步方法调用channel的Recv()方法，接收链接另一端发来的数据。
    2接收到消息后调用Run方法，run方法检查接收到的数据包是否有压缩，并指向相应的操作。
    3处理完压缩解压操作后交给RunDecompressedBytes，该方法比较厉害，调用绑定在Scene实体上的NetWorkConponent上的注册的解包器（默认是Bson）解包。
    4解包操作结束后就将其交给绑定在Scene实体上的NetWorkConponent上的messageDispatcher做转发。转发给相应的handler处理。
    
# 在大致了解了各组件的作用后，需要有一个大致的流程，把几个组件串联起来，实现客服端的网络功能：

## 网络流程如下：
### 1.	OpcodeTypeComponent加载封装好的网络消息。
### 2.	MessageDispatcherComponent加载所有的Handler
### 3.	开启网络监听。NetOuterComponent加入到Scene,我们使用udp,做如下操作：、
- a)	通过工厂从对象池中取出实例，调用父类Disposer的构造方法，加入到对象事件中心。
- b)	调用父类NetworkComponent的构造方法，创建对应协议的连接工厂（AService）。
- c)	调用NetOuterComponent的Awake()方法，指定网络协议、消息解包器和消息转发器。
- d)	NetworkComponent因为注册了Update,所以会在每一帧执行Update,Update中会执行service的update。service的update中会执行poller的Update，这个Update实际上是 每一帧都要轮询出所有的主机上的队列事件，并且调用其委托。这些事件包括：开始连接、接收数据、断开连接。这些事件的触发，会调用poller实体上的socket的对应的响应方法。 socket事件的委托是在创建UChannel时注册的。
- e)	UChannel的OnRecv()将接受到的消息放入到队列中，等待被Session轮询调用UChannel. Recv()方法取出。
- f)	取出消息后就会调用给NetOuterComponent指定的消息转发器。
由于是客户端，所以使用ClientDispatcher作为消息转发器。这个消息转发器在接收到帧循环消息后会进行客户端时间补偿处理。否则就直接将普通的rpc等消息交给MessageDispatcherComponent去做转发了。当然，帧循环消息最终也会交给MessageDispatcherComponent做转发。
- g)	Handle接收到消息后作出最终的处理。
- h)	D-g步骤是循环执行滴。
- i)	底层enet等不深入讨论，对我等透明。
- j)	到此，网络设施已经创建完毕，网络监听已经开启，并等待使用。
### 4.	创建对外连接。创建对外连接指的是连接到服务器。一般情况下从登陆开始创建对外连接。并且存储会话Gatesession。在整个客户端游戏生命周期中，Gatesession是一直存在的而且只有一份。
- a)	使用NetOuterComponent创建session。需指定要连接的地址和端口。这时候创建的session一般会是登录服务器，因为登录服务器在登录成功后会返回一个网关地址。
- b)	然后再根据这个网关地址创建游戏使用的session并且存入到SessionComponent中。
- c)	SessionComponent要加入到Scene实体保存。

### 5.	使用session通讯。
- a)	await SessionComponent.Instance.Session.Call<G2C_LoginGate>(new C2G_LoginGate() {Key = r2CLogin.Key})
- b)	详细参考doc中的《网络层设计》使用说明书。
### 6.	拓展网络功能以及建议。
- a)	这个嘛，仁者见仁啦。 
- b)	注意。使用c#的异步语法实现异步网络调用，是一件很舒服的事情，请详细研究异步语法。并使用之。
# - 登录流程示例讲解：
    //TODO
在掌握了ET客户端网络功能之后基本就掌握了ET的客户端框架。其他的一些框架特性是为了增加功能方便开发，当然如果实在掌握不了或者不喜欢用某个组件，可以用其他的方式实现，比如那个行为树。当然，一定要举一反三，通过学习研究网络组件，对整个et框架有个更深的认识，能够理解组件设计模式的精髓。组件包含数据和功能、实体包含组件，逻辑就是整个系统调用组件的过程。这也是最近闹得沸沸扬扬的ECS。另外，此处只是客户端的逻辑，服务端的逻辑TODO。




