golang 安全的tcp server_化繁为简,写一个简单好用的server
为什么要造轮子
目前很著名的轮子有libevent,boost等高并发的网络库,可以说著名的网络库我都用过,用过才知道当要实现一些定制化的功能时并不方便,不但要了解底层源码,而且还要进行适当的改造,总有种黑盒开发的感觉,所以在15年我就开始自己封装一些epoll,select模型,当时基于多路复用用reactor模式封装了betternet,虽然稳定性不如成熟的网络库,但是可以根据需求灵活修改网络层和应用层,这是难能可贵的。市面上也有一些成型的即时通信server,使用过kbengine,origine等集成度较高的server,当要实现一些心跳,逻辑检测,连接管理等需求时,还是要修改底层的源码,感觉很糟糕。18年接触golang,net包里封装的网络模型和协程管理,很完善的调度策略让我眼前一亮,所以考虑能不能基于golang的官方net包做一些框架上的设计,搭建一个高可用的网络服务。19年基于net包实现了wentby这个服务器,并发和稳定性都不错,最近又翻看了原来的代码,觉得很多地方可以精简一下,而且不想为了兼容别人的开发习惯降低服务器的效率,也不想增加复杂度,所以干脆做一个精简的server给自己用,只要他稳定高效就可以了,线程安全这种问题交由开发者考虑。读了redis网络服务那块也就500行,简约而不简单。
简单的设计
我的想法是尽可能减少线程切换的开销,尽可能精简的处理消息,同时也尽可能减少资源的开销,我的想法是这样的
当有新的连接建立时,I/O网络协程开辟新的协程,这个协程管理新的连接,负责读取客户端发送的数据。理论上每个连接建立后都有一个单独的协程为其服务,所以对于不同的连接,他们读取数据是并发进行的,无需加锁。同时在各自的协程里完成粘包处理,反序列化为一个逻辑请求包,将该逻辑请求投递的逻辑协程中。逻辑协程可以配置多个,也可以配置一个,建议配置一个,因为多协程处理共享区存在加锁问题,我在逻辑协程底层做了判断,如果逻辑协程数大于1则加锁,否则无锁。我觉得大部分的请求都是I/O密集型的,所以逻辑队列为1个足够,而且能保证应用层是线性处理的。当逻辑协程处理好逻辑请求后,将数据包投递到发送协程。这里发送协程数量也是可配置的,为了尽可能提升发送效率,我这里根据连接的id分配给指定协程发送,比如连接id为1的socket他的发送请求只交给发送携程1,这里用到了取余分配的原则。
用到了哪些技术和库
1 网络方面用到了go的原生net包。
2 协程分配和管理是自己实现的,协同和退出等通知都是通过channel实现的
3 配置和日志库用的beego的,主要是方便,懒得写文件管理。
4 由于go的网络层不会提供文件描述符,这里用到了uuid库生成string类型uid管理tcp
5 websocket用的原生net/websocket包,也没有单独开辟协程读写和处理,我觉得越简单越好
5 websocket每个请求其实是放在独立的协程中管理的,所以各协程处理逻辑时要加锁,这个我处理好了,应用层只需要安心写逻辑就可以。
效率怎么样
效率测试了一下,单节点8000以上的长连接,每个连接不间断收发请求未出现卡顿现象,延迟也都在10ms之内,而且未出现连接异常中断和丢包现象。
以下是写了个简单的测试协议,测试tcp粘包和压力
第二天看了下日志,跑了几十万行,最近又将服务器部署到云主机上了。
是否商用
目前用于公司内部呼叫系统的并发服务,基于webrtc实现信令控制,消息转发。
源码地址
目前代码已经开源
https://github.com/secondtonone1/wentmin
展望
随着经验的丰富,肯定会不满足现状的,以后会不断优化和扩充。
golang 安全的tcp server_化繁为简,写一个简单好用的server相关推荐
- 如何搭建python框架_从零开始:写一个简单的Python框架
原标题:从零开始:写一个简单的Python框架 Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发. 你为什么想搭建一个Web框架?我想有下面几个原因: 有一个 ...
- 用python写一个简单的web服务器
人生苦短,我用python 简洁高效,这才是理想的语言啊 分享一点python的学习经验-----如何用python写一个简单的web服务器 首先,我们需要简单地了解一下网络通信协议,这里用白话介绍一 ...
- 用java做一个简单记事本_用记事本写一个简单的java程序
用记事本写一个简单的java程序 第一步: 安装好jdk,并设置好环境变量. 桌面-计算机(右键)-属性-高级系统设置-环境变量-path-在变量值后加上:和jdk安装路径加上(路径即为C:\Prog ...
- ipad php mysql_如何用PHP/MySQL为 iOS App 写一个简单的web服务器(译) PART1
原文:http://www.raywenderlich.com/2941/how-to-write-a-simple-phpmysql-web-service-for-an-ios-app 作为一个i ...
- python123程序设计题说句心里话_用c++写一个简单的计算器程序
// 050305.cpp : 定义控制台应用程序的入口点. // // 050304.cpp : 定义控制台应用程序的入口点. // //四则运算 #include "stdafx.h&q ...
- 用java写一个简单的区块链(下)
用java写一个简单的区块链(下) 2018年03月29日 21:44:35 java派大星 阅读数:725 标签: 区块链java 更多 个人分类: 区块链 版权声明:本文为博主原创文章,转载请标明 ...
- 怎样用java写一个简单的文件复制程序
怎样用java写一个简单的文件复制程序 代码来源:https://jingyan.baidu.com/article/c35dbcb0d6f1398916fcbc07.html package Num ...
- 给 asp.net core 写一个简单的健康检查
给 asp.net core 写一个简单的健康检查 Intro 健康检查可以帮助我们知道应用的当前状态是不是处于良好状态,现在无论是 docker 还是 k8s 还是现在大多数的服务注册发现大多都提供 ...
- linux下Qt编写串口调试助手,如何在linux下用QT写一个简单的串口调试助手
如何在linux下用QT写一个简单的串口调试助手 QT5串口类 在QT5以前,编写串口一般使用的是qextserialport类,但在QT5之后有了QT自带的串口类SerialPort(串口基础类)和 ...
- 如何写一个简单的node.js C 扩展
node 是由 c 编写的,核心的 node 模块也都是由 c 代码来实现,所以同样 node 也开放了让使用者编写 c 扩展来实现一些操作的窗口. 如果大家对于 require 函数的描述还有印象的 ...
最新文章
- The Singleton of Design Pattern单态模式
- PyCharm无法启动的问题
- 安装Linux双系统取消快速启动,为什么在双启动时禁用Windows 8上的快速启动?
- 鸿蒙开发者目前人数,苹果时隔两年公布大中华区开发者数据:440万,增长76%
- matlab激光散斑散射半径测量,激光散斑测量2011412225741
- linux gpart 用法,gpart 使用笔记
- [SecureCRT] 解决 securecrt failed to open the host key database file 的问题
- 不使用ArcObjects直接查找SDE数据库信息
- 免费直播|1小时详解区块链技术
- vivo S9无法激活手机了vivoS9e怎么解锁平台刷机教程屏幕锁不记得了可以用这个方法教程重装系统固件软件S9手机如果已忘记密码可以自己学习升级降级USB操作了
- Win10家庭版禁用系统更新方法汇总及问题解决
- 手机幻灯片html代码,html5手机幻灯片制作手指滑动触屏手机幻灯片代码
- iOS 15 更新,图标改版
- Java8新特性之Optional类(附代码案例)
- 07中华小姐大赛落幕 20岁佳丽曾光夺冠
- Unity 2d 机器人的来回巡游
- linux基础知识全面总结,51CTO博客-专业IT技术博客创作平台-技术成就梦想
- 基于单片机的血压计c语言,基于AT89C51单片机的便携式数字血压计的设计
- 求职OMG——大学生就业指导与技能开发 第二章测试
- javaweb学习心得-01(西部开源-秦疆随堂笔记)