# 本篇中的名词都是作者基于自己理解做出的解释，非权威解释。
如果你找到权威解释，欢迎pr。

# 游戏服务器中那些被神话了的歧义的名词
关于游戏服务器架构的很多文章总是忽略或者误用某些名词，有意无意的掩盖了服务器设计中的真实细节，类似于数学教科书答案中的`显然` `易得`。个人理解，有不对的地方请指正。
1. `广播` 区别于UDP广播报，真实网络中协议层的广播报基本都被运营商和路由器等各个环节屏蔽了。服务器的广播实现就是把字节数组消息逐个发送给每个客户端连接，性能取决于代码，基本上都是异步广播方法+消息队列。
2. `转发` 多用于服务器之间。都是应用层转发，没有任何技术含量，接收->反序列化->确定转发目标->序列化->网络层发送。一些高性能的转发也仅仅是通过解析报头确定转发目标，省去反序列序列化的消耗。转发会产生一定量的服务器开销和延时。以致于我一度怀疑网关服务器存在的意义。
3. `buffer` 缓冲区，位于系统内核中（Kernel Mode），被网卡读取和写入的地方。应用程序将一个字节数组拷贝到发送缓冲区，然后网卡将数据发送到网络。网卡将收到的数据写入接收缓冲区，然后系统通知应用程序读取。

|      | cache                  | buffer                           |
| ---- | ---------------------- | -------------------------------- |
|      | 缓存区                 | 缓冲区                           |
| 用途 | 临时存放,快速读取      | 临时存放,零存整取                |
| 顺序 | 对象通常不要求有序     | 要求有序,先进先出,通常是字节数组 |
|      | 内存/文件              | 内存                             |
|      | 存在淘汰机制和生命周期 | 生产者消费者模式                 |



# 网络层中的名词：
## UserModeSendBuffer/用户态发送缓冲区
指用户态的要发送的字节数组：
- int Send(byte[] buffer, int size, SocketFlags socketFlags)中的buffer
- SocketAsyncEventArgs 中的 byte[] Buffer { get; }  
应用程序将要发送的内容变成一个字节数组，通过socket.send函数发送，
如果这个数组是每次都new新的，那么自然不存在缓冲区这个概念。通常我们会申请一个字节数组，反复使用，那么这个字节数组就是用户态发送缓冲区。

## UserModeRecvBuffer/用户态接收缓冲区
与发送对应，只用户态的一个字节数组，可以是new 的也可是从内存池申请的，通过recv函数将内核接收缓冲区的内容复制到这个数组中。通常这个字节数组我们也是反复使用而不是每次都new新的，注意用于接收过程中的SocketAsyncEventArgs的Buffer，可以看作用户态接收缓冲区。

## Socket SendBufferSize ReceiveBufferSize
指的socket内核缓冲区大小。
Socket 发送 UserModeSendBuffer 1024大小，将UserModeSendBuffer复制到内核缓冲区（默认8192），这时Send函数就可以返回了，系统负责将内核缓冲区的数据发送到 远端的接收内核缓冲区，远端调用Recv函数，将接收内核缓冲区的数据拷贝到UserModeRecvBuffer。
- 如何远端没有接收 内核发送缓冲区会一直累积，当累计满了，比如内核发送缓冲区大小8192，有8000字节对面没有接收，Socket继续Send UserModeSendBuffer 1024，由于内核发送缓冲区已经没有容量了，那么这次Send函数就会阻塞，卡住，直到对面接收。

## 序列化/反序列化 缓冲区
用于将对象转换成字节用的 字节数组，也有memorystream的形式。

# 完整发送过程
发送object--序列化/将obj变成字节数组这个字节数组就是序列化缓冲区--拷贝到UserModeSendBuffer--Socket Send/拷贝到内核缓冲区--网线--接收内核缓冲区--Socket Recv/拷贝到UserModeRecvBuffer--反序列化/拷贝到反序列化缓冲区--收到object。


# 本库中的名词
本库高度优化了上述发送过程，上述流程不能与本库代码对应。
## 发送管道/SendPipe
可能是一段连续内存，也肯能是一系列内存片段，是object消息经过序列化后的东西，正在等待Socket发送的，这些东西的有序容器。作用是取代上面的UserModeSendBuffer。
## 接收管道/RecvPipe
接收到的字节内容，经过分离粘包处理后，一个个代表完整包的字节数组或片段，此时还没有开始反序列化。保存这些内容的区域称为接收管道。
作用是取代上面的UserModeRecvBuffer。

# 参考链接
- [TCP的发送缓冲区和接收缓冲区](https://www.cnblogs.com/saryli/p/9821058.html)  
- [socket使用TCP协议时，send、recv函数解析以及TCP连接关闭的问题](https://www.cnblogs.com/lidabo/p/4534755.html)
- [关于TCP/IP，必须知道的十个知识点](https://blog.csdn.net/u012371712/article/details/80795297)
- [Unity.多人游戏网络.高级术语](https://docs-multiplayer.unity3d.com/netcode/current/reference/glossary/high-level-terminology)

# 连接/会话/频道 Socket/Session/Channel

他们之间概念很模糊。主要区别是断开后该实例能否重连   
- 连接Socket由于内部逻辑复杂，断开后不能重连，需要构造新对象。
- 会话Session断开后通常可以重连，可以认为内部包含Socket，并且Socket可以变动。  
    + 在Session不活动时，内部Socket可能已经断开，在下次活动是重新建立。 
    + 可以认为是长连接。
- 频道Channel依赖Session的高级功能，多个channel公用一个Session，通常用于消息分发和业务隔离。

一个客户端对应一个Session是最合适状态。

在本库中，IRemote 不应该继承IConnectable，不关心连接过程， 在语义上是Session级别的接口，而TcpRemote算是Socket的增强，是连接级别的，因为Tcpremote很难实现实例重连功能，需要构造新对象。UdpRemote是无连接的，自然就是Session级别的。

用户在使用过程不需要关注连接状态，由实现者负责。