- 博客(129)
- 资源 (5)
- 收藏
- 关注

原创 B树 解析与源码
概念B树,是普遍运用于文件系统和数据库的一种多叉(即,每个非叶子结点可以有多个孩子)平衡查找树。数据库索引为什么采用B树/B+树结构?数据库索引存储在磁盘上,当数据库的数据量比较大时,索引可能高达几G,甚至更多。所以在利用索引查找时,不会一次性把整个索引加载到内存,而是每次只加载一个磁盘页(这里的磁盘页对应索引树的结点)。若索引树采用二叉树结构,则一个页面只能存放一个值。因此
2018-01-31 11:17:10
6036
1

原创 protobuf 如何解析(大于64MB)超大报文
为了阻止恶意用户发送超大报文,而导致int溢出或服务端为解析报文而分配大量内存致使内存耗尽,protobuf规定int溢出的默认值阈值是64MB(理论是512MB)。因此,当调用ParseFromString(str)方法时,若str的长度>64MB,返回会返回失败。注意到protobuf中包含这样一个函数:void SetTotalBytesLimit(int total_bytes_limit,
2017-10-26 14:10:44
9240
3

原创 开机启动C++实现
// 程序开机自动启动void autostart(){ HKEY hKey; QString strRegPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"; //1、找到系统的启动项 if (RegOpenKeyEx(HKEY_CURRENT_USER, strRegPath.toStdStr
2017-06-03 14:12:02
9579
4
原创 静态链接与动态链接原理
示例程序 main.c:#include <stdio.h>void print_banner(){ printf("Welcome to World of PLT and GOT\n");}int main(void){ print_banner(); return 0;}源文件想变成能够在内存中运行的程序,需经历编译、链接、载入3个步骤。编译:gcc -Wall -g -o main.o -c main.c -m32链接:gcc -o
2022-02-09 17:58:02
2762
原创 QUIC linux编译
一、源码下载Chromium源码本身非常大,加之国内由于墙的存在,导致源码的下载难上加难。因此,本文直接使用文章:如何下载Google Chromium源码 提供的源码,百度网盘下载链接:https://pan.baidu.com/s/1UCi4blsdGrqHQRRIcYnW6w ,提取码:s4yr。链接中包含8个 chromium.tar.gz* 文件和1个 depot_tools.tar.gz,前者即为 Chromium 分片后的源码,后者为 Google 代码管理工具包。chromium.t
2021-12-23 20:45:00
2696
原创 ptmalloc VS tcmalloc VS jemalloc 原理及对比测试
一、ptmalloc1.1 特点使用空闲链表bins管理用户free掉的内存作为下次使用,而不是直接还给os,可避免频繁的系统调用,降低内存分配的开销;若分配区锁竞争激烈,会导致非主分区快速增长,当非主分区数量达到阈值之后,会因为无法分配新的非主分区而导致线程阻塞,从而影响ptmalloc的效率;先申请的内存先释放会导致内存无法收缩。这是因为ptmalloc的内存收缩是从Top chunk开始的,若Top chunk相邻的内存未释放,则Top chunk以下的所有内存都不能释放,从而导致内存泄漏;
2021-05-21 20:42:49
3823
原创 skynet master/slave 测试
master / slave 配置文件均沿用前一篇文章:skynet master/slave 模式。一、测试脚本main.lua:根据配置文件判断当前节点是否为 master,并对指定地址进行监听。local skynet = require "skynet"local socket = require "skynet.socket"local cluster = require ...
2020-05-05 14:23:38
771
1
原创 skynet master/slave 模式
一、相关配置项 harbor节点唯一性编号,1~255 之间的任意整数,因此一个 skynet 网络最多支持 255 个节点。若某个 slave 意外退出,则对应的 harbor 会被废弃,不可再使用(即使该 slave 后续重启),这样是为了防止网络中其它服务还持有这个断开的 slave 上的服务地址,而一个新的进程以相同的 harbor 接入时,是无法保证旧地址和新地址不重复的。也就...
2020-05-04 19:58:02
1390
原创 skynet:queue
在 skynet 中,当服务收到消息后,skynet 会起一个协程来处理消息,当某个协程涉及到异步让出执行时,skynet 会继续执行下一条消息,等到该协程的醒消息到达时便继续执行。有时候,我们想保持处理客户端发送消息的顺序性,比如客户端依次发送消息 a 和 b ,而由于某种需求,我们又要保证 b 一定要在 a 之后返回,这个时候就需要用到 skynet.queue。使用方法:local q...
2020-04-30 15:05:20
1864
1
原创 skynet:服务重入问题
一个服务在接收到请求后,会对该请求进行处理,在处理的过程中,能同时接收并处理后到达的请求。一、测试脚本修改文章:skynet:session 中的测试脚本:echoluamsg.lua 与 testforkcall.lua:echoluamsg.luaskynet = require "skynet"require "skynet.manager"local command = {...
2020-04-29 13:52:08
890
原创 skynet:skynet.call() 失败
skynet.call() 是一个阻塞函数,服务使用 skynet.call 发出请求后会等待应答,此时: 若响应服务退出(调用skynet.exit),会自动给未答复的请求发送一个 error 消息,告诉它可以从 skynet.call 阻塞返回了,请求的服务会直接报一个错误; 若响应服务正常,但并未返回响应,则 skynet.call 阻塞会返回,同时请求的服务会收到一个告警信息:...
2020-04-29 09:03:59
1101
原创 skynet:skynet.response
在前面的文章:skynet:session 中,已经使用过 skynet.ret / skynet.retpack 对消息进行应答。但这两个函数有一个使用限制,即:消息接收与消息应答必须在同一个协程里完成,也就是说:请求被哪一个协程接收,就必须在这个协程响应。这是因为在 skynet 中,当一个服务收到一个消息的时候,会启动一个协程来处理,并把协程句柄与发送消息的服务地址进行一一对应记录在 ta...
2020-04-29 08:26:52
1121
原创 skynet:session
当一个服务使用多个协程发送消息时,可能出现多个协程都在等待响应。那么当某个响应到达时,应该唤醒哪个协程,可通过 session 来判断,这是因为在 skynet 中,session 能保证消息在本服务中的唯一性,从而使消息与响应一一对应起来。但 session 只有在使用 skynet.call 或 skynet.rawcall 发送消息时才有意义。一、测试脚本echoluamsg.lua...
2020-04-28 15:51:44
916
原创 skynet:udp
skynet 为 udp 协议做了有限的支持。和 tcp 协议不同,udp 协议不需要阻塞读取。这是因为 udp 是不可靠协议,无法预期下一个读到的数据包是什么(协议允许乱序和丢包),因此 skynet 的 udp 协议封装采用的是 callback 的方式。一、服务端测试main.lualocal skynet = require "skynet"local socket = requ...
2020-04-28 12:30:40
981
原创 skynet:TCP主动连接端
前面的文章讲过,如何使用 socket 建立 tcp 监听:#监听指定地址:ip:portsocket_id = socket.listen("ip:port")#当监听到连接时,自定义函数:accept 会被触发socket.start(socket_id, accept)function accept(socket_id, addr) skynet.error(addr ...
2020-04-27 20:58:19
962
原创 skynet:fork
skynet 是多线程框架,此外在 skynet 中,每个服务对应一个 lua 虚拟机,一个虚拟机上可以跑多个协程,但同一时刻只能有一个协程,每条消息处理由协程来完成。在 skynet 中,线程创建方式:skynet.fork(func,…)一、测试main.lualocal skynet = require "skynet"skynet.start(function() ...
2020-04-27 15:54:58
2651
原创 skynet:自带网关服务
一、main() 启动 watchdogexamples/main.lua,会首先启动一个 watchdog: local watchdog = skynet.newservice("watchdog") skynet.call(watchdog, "lua", "start", { port = 8888, maxclient = max_client, nodelay = t...
2020-04-25 12:51:42
643
原创 skynet:agent
gateserver 用于管理网络连接,也可以读取网络数据,但它并没有提供发送网络数据相关的写功能,而涉及请求处理与响应一般交给 agent 服务(agent 服务可以由一个普通服务来充当)。一、agent 服务myagent.lualocal skynet = require "skynet"local netpack = require "skynet.netpack"local s...
2020-04-24 19:58:37
988
原创 skynet:网关服务 二
一、控制客户端连接数在启动网关时,可指定当前服务的最大连接数,以避免大量用户登录到该服务。启动网关服务后,运行三个 socketclient 客户端,结果如下:可以看到,第三个客户端连接成功后,被立即关闭。二、gateserver 其他回调函数--[[ gateserver监听成功后,会调用此接口,可用来进行一些初始化操作。 source:请求来源地址,conf:开启 gates...
2020-04-24 12:03:34
1121
原创 skynet:网关服务与封包/解包
TCP 是基于数据流的,但一般需要以带长度信息的数据包来做数据交换,skynet 提供了一个通用模板 lualib/snax/gateserver.lua 来启动一个网关服务器,gateserver 做的就是这个工作。一、编写网关服务mygateserver.lualocal skynet = require "skynet"local gateserver = require "snax...
2020-04-23 18:47:44
2288
原创 skynet:httpserver 研究
skynet.newservice(name),用于创建新服务,会调用服务初始化函数:skynet.start(); skynet.call(“服务名”,“lua”,“方法名(函数名)”,参数1、参数2…):向指定服务发送lua类型消息,阻塞函数; skynet.register_protocol{}:将指定的协议记录到一张表里面,后续可通过协议名或id找到此协议。相关属性:...
2020-04-20 19:51:41
575
原创 skynet:调用c模块
一、定义 c 模块#include <lua.h>#include <lauxlib.h>static int add(lua_State *L) { float a1 = lua_tonumber(L, 1); float a2 = lua_tonumber(L, 2); lua_pushnumber(L, a1 + a2); re...
2020-04-19 10:24:23
458
原创 skynet:服务间发送消息
skynet 是单进程多线程框架,每个 lua service 独立运行在自己的 lua vm 里,而本篇文章要实现的是让一个 service 发送消息,另一个 service 处理消息。一、skynet 启动新 servicelocal skynet = require "skynet"skynet.start(function() skynet.newservice("myservi...
2020-04-17 14:17:48
1076
原创 skynet:服务间相互调用与转交socket控制权
socket.abandon(id):用于清除 socket id 在本服务内的数据结构,但并不关闭这个 socket ,可用于向其他服务转交socket控制权。目录结构与文章:skynet:socket 测试 保持一致,区别在于修改文件:service_gate.lua,并在 service 目录下新增文件:agent1.lua。一、service_gate.lualocal skynet...
2020-04-17 13:25:46
468
原创 skynet:服务的别名
skynet 由服务组成,并可使用字符串对服务进行命名,但服务的名字不可重复。相关函数: newservice(name, …):启动一个名为 name 的新服务(这就是风云提到的沙盒,即各服务独立运行,互不影响,但服务之间可相互调用); uniqueservice(name, …):启动一个唯一服务,若该服务已启动,则返回已启动的服务地址; queryservice(name):查询一个...
2020-04-17 10:51:52
608
原创 lua 语法笔记
1、脚本创建文件:HelloWorld.lua,内容如下:print(“Hello World!”)执行脚本:lua HelloWorld.lua2、注释单行注释(两个减号):– 注释多行注释:–[[多行注释多行注释–]]3、变量变量不需要事先申明变量默认为全局变量,若在赋值时,指定了 local,则为局部变量:local b = 5删除变量,只...
2020-04-16 15:41:05
200
原创 skynet:分离项目代码与 skynet 源码
在前面的文章:skynet 测试 中,自己的代码与 skynet 源码混合在一起,由于我们不是对 skynet 进行二次开发,所以最好将两者分离开来。一、自定义项目目录在 /root 下新建文件夹:server_01,server_01 结构如下: service:存放服务脚本(本文测试依然采用前一篇文章的 socket 测试脚本); config :存放配置文件; log:存放日志...
2020-04-15 20:05:08
288
原创 skynet:socket 测试
一、demo1、目录准备 新建 server 目录,将 skynet 目录拷贝到 server 目录下; 在 skynet 目录同级新建 game 目录; 在 game 目录中新建3个文件,config、main.lua 和 service_gate.lua,其中 log 目录是存放日志文件,最终目录结构如下:2、文件 service_gate.lua 内容local skyne...
2020-04-14 12:49:15
810
原创 skynet 编译问题集锦
下载 skynet 源码:https://github.com/cloudwu/skynetskynet 编译很简单,直接切换到 skynet 目录后,执行命令:make linux问题一:git 命令不存在解决方法:https://packages.debian.org/stretch/git问题一:fatal: Not a git repository (or any of t...
2020-04-14 10:40:36
1838
原创 skynet worker 线程
一、创建若干 worker 线程skynet 启动时,会创建若干 worker 线程(由配置指定)并指定线程权重:static voidstart(int thread) { pthread_t pid[thread+3]; struct monitor *m = skynet_malloc(sizeof(*m)); memset(m, 0, sizeof(*m)); m->...
2020-04-13 15:38:39
713
原创 WebRTC研究:丢包与抖动
1、累计收包、重传包等信息,并计算抖动:void StreamStatisticianImpl::UpdateCounters(const RTPHeader& header, size_t packet_length, ...
2020-04-07 15:39:10
1300
原创 WebRTC研究:sending_
RTCPSender.sending_ 默认为 false,即当前为接收端。RTCPSender::RTCPSender( bool audio, Clock* clock, ReceiveStatistics* receive_statistics, RtcpPacketTypeCounterObserver* packet_type_counter_obser...
2020-04-02 15:09:33
213
原创 WebRTC研究:rrt 时间 之 CallStats
在之前的文章:WebRTC研究:rrt 时间 之 再次处理以供重传等功能使用 中讲到,ModuleRtpRtcpImpl::Process() 会将 RRT 时间与当前时间一起存入 CallStats 对象的 reports_ 集合中,然后由 CallStats.Process() 计算出重传等应用中所使用到的 avg_rtt_ms_ 与 max_rtt_ms_,那么本篇文章将会介绍此部分计算逻辑...
2020-04-02 14:14:05
642
原创 WebRTC研究:rrt 时间 之 再次处理以供重传等功能使用
在之前的文章:WebRTC研究:rrt 时间计算 之 接收 SR / RR 包 中讲到,sender 在接收到 RR 包后,会根据包体所携带的 DelayLastSR / LastSR 计算出 RRT 时间,但这个 RRT 时间并不能直接应用到重传等功能中,必须经过二次处理。二次处理在 ModuleRtpRtcpImpl::Process() 中完成,这个函数在之前的文章:WebRTC研究:rr...
2020-04-02 13:11:43
1098
原创 WebRTC研究:rrt 时间计算 之 发送 SR / RR 包
一、ModuleRtpRtcpImpl::Process() 会定时处理 SR/RR 包发送、bitrate、rrt 等事宜,处理时间间隔为 5 ms:int64_t ModuleRtpRtcpImpl::TimeUntilNextProcess() { /* last_process_time_:上次调用 Process() 的开始时间 理论上是,在本次调用 Pro...
2020-04-01 22:45:53
1833
原创 WebRTC研究:rrt 时间计算 之 接收 SR / RR 包
一、当客户端收到一个 RTCP 包时,会根据包类型调用分别调用不同的处理函数。对于 SR 和 RR 包,都会交由 HandleSenderReceiverReport() 处理:int32_t ModuleRtpRtcpImpl::IncomingRtcpPacket(const uint8_t* rtcp_packet, const size_t length) --------- rtp_r...
2020-04-01 21:36:31
1550
原创 C++ 遍历数组或集合
遍历数组时,除了常用到的 for(;???? 之外,还可以通过 for( : ),区别在于:前者使用索引遍历,后者直接使用元素遍历。 int reports[] = { 1, 2, 3, 4, 5, 6 }; for (int value : reports) { std::cout << value << std::endl; } std::list<...
2020-03-31 15:38:40
3359
原创 WebRTC研究:audio 如何发送需要重传的数据
当 WebRTC 收到一个 RTP 包重传请求(一个请求中可能包含多个要重传的 seq)时: 首先,判断是否有足够的带宽来发送需要重传的包,是的话,则直接拒绝本次重传。判断依据:最近 1s 内且最近 60次 (即默认以最近 1s 为参考对象,若最近 1s 内有 60 或以上次数的重传,则以最近 60 次为参考对象)发送的总位数 是否小于 目标比特率(target_bitrate)* 时间长度...
2020-03-30 21:17:40
332
原创 WebRTC研究:audio 重传
一、获取需要重传的包序列号std::vector<uint16_t> NackTracker::GetNackList(int64_t round_trip_time_ms) const { RTC_DCHECK_GE(round_trip_time_ms, 0); std::vector<uint16_t> sequence_numbers; for (N...
2020-03-28 12:01:32
395
原创 WebRTC研究:audio 丢包判断
当收到一个包时,丢包判断原理:1、将 当前收包序列号:sequence_number 从丢包集合 nack_list_ 中剔除;2、将 sequence_number 与 最近收到的新包:sequence_num_last_received_rtp_ 对比,判断当前包是否为重传或乱序包。如若是的话,直接终止判断,否则继续;3、对比 当前包 与 最新收到的包 的序列号与时间戳,更新每个包的样本...
2020-03-27 16:40:26
505
Windows Redis 集群搭建工具
2017-04-19
Win7 + VS2013 + FastCGI + gSOAP搭建 WebService
2017-01-06
Apache2.2 + FastCGI + gSOAP搭建 WebService工具
2017-01-06
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人