IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Kinx TCP服务框架 -> 正文阅读

[网络协议]Kinx TCP服务框架

前两天在小破站看到zinx框架的教程,于是跟着学了学,实现完了换了个名叫 Kinx hhhhh~。有意愿的可以star一波~?GitHub - k-si/Kinx: tcp服务框架

附一张整体架构图:

设计思想

tcp通信在代码层面上是非常简单的,因为几乎所有的语言都提供了套接字,套接字就是对底层操作系统通信细节的封装,只需要调用封装好的api,就可以完成复杂的通信操作。tcp通信典型的有server-client模式,对于TCP服务器来说扮演的肯定是server的角色。它通过监听端口,循环阻塞获取连接句柄,然后通过句柄进行发收消息。客户端只需要拿到服务端的ip和端口,使用tcp协议连接上服务器,开始发送接受消息即可。

但是对于服务器来说,是需要提供一定的并发量的,不能一个server只给一个client使用吧。所以肯定是多线程的给每个client提供服务。ok,到这我们就能确定,每一个client的连接,都需要一个goroutine/thread进行处理。连接成功之后,开始处理业务,一般业务划分为读/写两种,那么对于每一个连接的处理,读和写的处理必须保证是同时的,不能写完一个再读一个,应该是读和写互不影响的。由此我们可以确定,对于每一个连接,我们需要分别再开两个线程来处理读写业务。

一个关键问题

我们再考虑一个问题,服务端提供的服务一定是有限的,不可能有一亿个客户端来连接,服务端就必须开辟一亿个goroutine来进行处理吧,服务的机器性能不允许,即使能开一亿个线程,线程之间的切换会消耗大量的线程,反而得不偿失。

有什么解决办法呢?你可能会说,我们可以限制client连接数量,一旦达到某个值,就拒绝连接。这当然可以,但是就是有点浪费资源。为什么?每个连接都要开一个goroutine,有的连接可能业务非常简单,这样它的3个goroutine空闲的时间将非常多,我们希望的是充分利用每一个goroutine,让他们不能停歇(心疼goroutine一秒)。为实现这个目的,我们使用线程池+任务队列来限制过多的goroutine。

假设有100个client连接,那么会启动100个goroutine处理连接,然后每个连接启动2个goroutine处理读写,这一共就是300个goroutine。这其中最耗时的操作是什么呢?应该是处理的读业务,一般写业务是比较简单的,麻烦的是读取一个数据之后进行的逻辑业务,写业务只是把结果写回就可以了。所以关键就在这100个读业务goroutine上。

我们可以开辟一个线程池,在启动server的时候就初始化线程池,存放10个线程,在处理读业务的时候,将任务push给一个线程,并通过某种均衡算法使得这10个线程处理的任务量是均衡的。那么我们就必须为每一个线程绑定一个任务队列,任务队列在golang中直接使用channel实现就好,非常方便~

那么现在再有100个client连接后,每个连接的业务任务都会分配到这10个线程中,每个线程都是100%进行工作的,当然也可能不是100%,这住要取决于均衡算法的实现。但是整体来说资源的利用率肯定是大大提升了,整体的处理速度也不一定会差很多。这种实现方式,很像GMP模型中的调度器,每一个p就是一个任务,由调度器决定p分给哪个内核线程。可见处理问题的思路是相同的~

另一个小问题

涉及tcp通信不可避免的就是tcp黏包问题,在代码中读取数据实际上是需要一个byte数组一个byte数组这样读的,并不能是像水流一样源源不断的读取,肯定是有截断的。那么万一传输的数据比较长,中间被截断了,怎么给联系起来呢?这里就需要我们自定义一种协议,有一种简单的TLV协议,即每次发送的消息应该包含消息类型、消息内容、消息长度这三个变量。并且server和client都要遵守这个协议。这样在读取的时候,就可以判断数据的长度,然后再从连接中读取正确长度的数据,并且数据类型还能方面的指示数据的业务类型,方便消息的分类。

一些设计小心思

每个连接的读写业务是需要沟通的,读业务读取数据,并处理,最终结果需要输出给写业务,这就用到了channel,这非常的合乎时宜,channel就是用来做不同goroutine之间通信的。处理完的数据直接塞到channel里,然后写业务轮询读取就好了。

对于框架来说,是给人使用的,它本身并不能实现具体的业务逻辑。框架一般都会提供一个接口,开发者使用时可以专注于业务的处理,而不是钻这些并发、消息处理上的牛角尖。所以Kinx是需要提供这样一个函数或者接口,开发者在其中实现具体业务逻辑,然后服务运行时就会将函数嵌入到框架中,自然就处理了业务。这个概念对应框架中的router模块,该模块提供了prehandle,handle,posthandle三个函数来对应处理业务前、处理业务时、处理业务后三个阶段。模块的具体实现也挺有意思的,router结构体带有这三个函数,框架获取连接后调用router的三个函数.......这里不太好用文字描述,直接去看代码吧~

另外就是一些模块的抽象,怎么去抽象、然后将抽象实现。这就对应面向对象设计中的结构体/类,和对应的方法了。

?

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-11-22 12:42:59  更:2021-11-22 12:44:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 7:26:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码