crtmpserver 运行过程简明分析

2 篇文章 0 订阅
2 篇文章 0 订阅
crtmpserver.cpp main()函数下的执行过程:

1. SRAND(); //随机数产生过程
2. InitNetworking(); //初始化异步socket资源,调用接口WSAStartup()
3. Variant::DeserializeFromCmdLineArgs(argc, argv, gRs.commandLine) //把命令行带入的参数,序列化到Variant gRs.commandLine
4. NormalizeCommandLine(configFile) //把序列化的参数检查一遍,并把按string类型存储的转化为实际类型存储string configFile
5. Initialize() //主要用于初始化运行前的环境、状态及完善配置信息
6. Run() //循环监听运行socket的状态,并及时进行服务处理
7. Cleanup() //系统退出时,需要做的一些清理工作

crtmpserver.cpp Initialize()函数下的执行过程:

1. Logger::Init(); //用于实例化一个Logger对象
2. Logger::AddLogLocation(pLogLocation); //根据命令行有无”–use-implicit-console-appender”,去添加一个ConsoleLogLocation * pLogLocation 对象。
3. gRs.pConfigFile = new ConfigFile(NULL, NULL); //实例化一个空的配置文件对象
4. splitFileName(configFilePath, fileName, extension); //分割文件名和文件类型
5. gRs.pConfigFile->LoadLuaFile(configFilePath, (bool)gRs.commandLine[“arguments”][“–daemon”]) //load一个lua配置文件,并把所有配置信息放入到pConfigFile指向的对象的Variant _configuration中,并检查配置参数的合理性。
6. gRs.pConfigFile->ConfigLogAppenders()
遍历FOR_MAP(_logAppenders, string, Variant, i)变量,并根据配置信息创建的实例对象(eg. ConsoleLogLocation, FileLogLocation)。
7. IOHandlerManager::Initialize()
主要是把FdStats IOHandlerManager::_fdStats、fd_set IOHandlerManager::_readFds
fd_set IOHandlerManager::_writeFds三个对象初始化,
_pTimersManager = new TimersManager(IOHandlerManager::ProcessTimer)、_isShuttingDown = false,其中_fdStats为fd的统计信息对象,_readFds为读取的socket集,_writeFds为写出的socket集。
8. gRs.pConfigFile->ConfigModules()
遍历FOR_MAP(_applications, string, Variant, i)变量,把map<string, Module> _modules填充满,并调用Module.Load()函数,把每个应用模块对应的dll加载进来,并根据加载的dll句柄,获取相应的接口函数指针去初始化getApplication、getFactory两个函数指针。
9. gRs.pProtocolFactory = new DefaultProtocolFactory()
实例化一个DefaultProtocolFactory对象,DefaultProtocolFactory—>BaseProtocolFactory(构造函数中只产生一个uint32_t _id)。
10. ProtocolFactoryManager::RegisterProtocolFactory(gRs.pProtocolFactory)
把第9步创建的默认协议工厂对象注册到协议工厂管理器中,注册过程中,首先检查协议工厂_id是否已经存在于_factoriesById中,如 果没有就继续注册下去,协议工厂调用HandledProtocolChains()接口,返回支持的协议链名的向量,并检查每个协议链名是否存在于_factoriesByChainName中,如果没有就继续注册下去,然后协议工厂调用HandledProtocols()接口去返回支持的协议id的向量,并检查每个协议id是否存在于_factoriesByProtocolId变量中,如果没有就注册成功。

map<uint32_t, BaseProtocolFactory *> ProtocolFactoryManager::_factoriesById;
map<uint64_t, BaseProtocolFactory *> ProtocolFactoryManager::_factoriesByProtocolId;
map<string, BaseProtocolFactory *> ProtocolFactoryManager::_factoriesByChainName;

11. gRs.pConfigFile->ConfigFactories()
遍历FOR_MAP(_modules, string, Module, i)变量,根据第8步获得的getFactory函数指针去生成一个协议工厂赋值给Module中的协议工厂变量BaseProtocolFactory *pFactory,并把此协议工厂变量注册到协议工厂管理器当中。
12. gRs.pConfigFile->ConfigAcceptors()
遍历FOR_MAP(_modules, string, Module, i)中的变量,再遍历FOR_MAP(config["acceptors"], string, Variant, i)中的变量,根据
acceptors对应的每一个形如

{
    ip="0.0.0.0",
    port=1935,
    protocol="inboundRtmp"
}

的变量执行BindAcceptor()接口,过程如下:
1. 首先根据协议链名调用
vector<uint64_t> chain = ProtocolFactoryManager::ResolveProtocolChain(node[CONF_PROTOCOL]);生成
协议链名对应的协议id所构成的向量,然后判断向量的第一个元素是TCP还是UDP协议去生成相应的TCPAccpetor对象。
2. TCPAcceptor *pAcceptor = new TCPAcceptor(node[CONF_IP], node[CONF_PORT], node, chain);
初始化IOHandler的_id、_type = IOHT_ACCEPTOR,并记录端口、IP地址、协议id向量、acceptor子节点参数;并把此IOHandler注册到IOHandlerManager中,注册过程就是:
首先,根据IOHandler的_id注册到map<uint32_t, IOHandler *> IOHandlerManager::_activeIOHandlers;
然后,根据IOHandler的_type调用_fdStats.RegisterManaged(pIOHandler->GetType());注册到_fdStats中,更新其统计。
3. 调用pAcceptor->Bind()接口,
首先,完成socket创建,并赋值给_inboundFd、_outboundFd变量;
然后,setFdOptions(_inboundFd, false),
然后,绑定bind(_inboundFd, (sockaddr *) & _address, sizeof (sockaddr)
最后,监听listen(_inboundFd, 100)
13. gRs.pConfigFile->ConfigInstances()
do nothing, windows server don’t support multiple instance.
14. IOHandlerManager::Start()
do nothing.
15. gRs.pConfigFile->ConfigApplications()

1. pApplication = getApplication(config); // 应用对象的创建

遍历FOR_MAP(_modules, string, Module, i)中的_modules,调用每个Module的接口函数ConfigApplication(),在其内部调用第8步配置的函数指针getApplication去生成应用程序对象(eg. AdminApplication),应用程序对象都是继承自BaseClientApplication类。
在此对象创建过程中,AdminApplication只是把_pRTMPHandler = NULL (类型为RTMPAppProtocolHandler *),
然后其基类对象BaseClientApplication完成的事情就比较多:_id(应用id编号)、_configuration(此应用的配置)、_name(应用名)、_aliases(应用程序别名)、_isDefault(是不是默认应用)、
_allowDuplicateInboundNetworkStreams(是否允许复制入站网络流)、_hasStreamAliases(流别名)
基类对象有一个类型为StreamsManager类的变量_streamsManager(this = 实例对象AdminApplication) ,其构造函数也仅仅是记录实际的应用_uniqueIdGenerator = 1、_pApplication = AdminApplication;

2. ClientApplicationManager::RegisterApplication(pApplication) //应用对象添加到ClientApplicationManager

a. 检查应用的id是否在_applicationsById; b. 检查应用的name、aliases是否在_applicationsByName c. 检查是否是默认应用

3. pApplication->Initialize()

a. BaseClientApplication::Initialize() //do nothing
b. _pRTMPHandler = new RTMPAppProtocolHandler(_configuration) (BaseAppProtocolHandler*)
RTMPAppProtocolHandler()构造函数do nothing
BaseRTMPAppProtocolHandler()构造函数记录以下变量值:
_keyframeSeek、_clientSideBuffer、_seekGranularity、_mediaFolder、_renameBadFiles、_externSeekGenerator、
_enableCheckBandwidth、_lastUsersFileUpdate等变量
BaseAppProtocolHandler()构造函数记录_configuration = configuration
c. RegisterAppProtocolHandler(PT_INBOUND_RTMP, _pRTMPHandler)
往应用程序的map<uint64_t, BaseAppProtocolHandler *> _protocolsHandlers添加Handler,并设置此Handler的应用为应用对象本身。
d. RegisterAppProtocolHandler(PT_OUTBOUND_RTMP, _pRTMPHandler)

4. pApplication->ParseAuthentication()

认证暂时不做分析,等以后有时间再做处理。

5. pApplication->ActivateAcceptors(acceptors)

把应用中acceptors的每一个acceptor都激活,根据acceptor的类型去做相应的处理,以IOHandler的类型为IOHT_ACCEPTOR做讲解:
a. 首先设置此IOHandler的应用为本应用对象(this)
b. 调用此IOHandler的StartAccept()接口,主要是设置好map<int32_t, map<uint32_t, uint8_t> > _fdState关于此Handler,然后更新FdSets. <Handler关联的socket, <Handler的id, Handler对应的状态>>

16. installQuitSignal(QuitSignalHandler) //注册好退出处理函数

crtmpserver.cpp Run()函数执行过程
1. IOHandlerManager::Pulse() //根据此函数的执行结果决定循环是否继续

a. 清空_readFdsCopy、_writeFdsCopy,
b. 把_readFds、_writeFds赋值给_readFdsCopy、_writeFdsCopy
c. 再调用select(MAP_KEY(--_fdState.end()) + 1, &_readFdsCopy, &_writeFdsCopy, NULL, &_timeout)进行socket轮询
d. 遍历FOR_MAP(_activeIOHandlers, uint32_t, IOHandler *, i),检查IOHandler所对应的socket是否在其中,
FD_ISSET(MAP_VAL(i)->GetInboundFd(), &_readFdsCopy) 或者 FD_ISSET(MAP_VAL(i)->GetOutboundFd(), &_writeFdsCopy)
e. 如果存在fdSets中,就调用相应IOHandler的OnEvent
e.1. accept(_inboundFd, &address, &len)
e.2. setFdOptions(fd, false)
e.3. BaseProtocol *pProtocol = ProtocolFactoryManager::CreateProtocolChain(_protocolChain, _parameters)
e.4. 根据accept返回的fd创建TCPCarrier()实例对象,构造函数里面就把设置为可读数据状态、注册到IOHandlerManager中
e.5. pTCPCarrier->SetProtocol(pProtocol->GetFarEndpoint());设置pTCPCarrier的协议为远点协议TCPProtocol
e.6. pProtocol->GetFarEndpoint()->SetIOHandler(pTCPCarrier); 设置远点协议的IOHandler为TCPCarrier
e.7. pProtocol->GetNearEndpoint()->SetApplication(_pApplication); 设置近点协议的应用为本身应用对象(AdminApplication)
e.8. pProtocol->GetNearEndpoint()->GetOutputBuffer()不为NULL,则pProtocol->GetNearEndpoint()->EnqueueForOutbound();
举例:GetNearEndpoint返回InboundRTMPProtocol对象,GetOutputBuffer()实际是调用BaseRTMPProtocol对象中的IOBuffer _outputBuffer;EnqueueForOutbound()实际调用_pFarProtocol->EnqueueForOutbound(),_pFarProtocol为TCPProtocol(),调用TCPProtocol::EnqueueForOutbound(),即是_pCarrier->SignalOutputData(),此函数只是ENABLE_WRITE_DATA
f. 如果在OnEvent()中处理失败就调用EnqueueForDelete()进入状态清理工作,主要是清理_fdState中关于此socket的状态(相应的去设置_readFds、_writeFds的状态),并把IOHandler加入到_deadIOHandlers MAP中

然后在TCPCarrier中做数据的收发动作!根据读写进行相应的操作:
读:

TCPCarrier的_pProtocol为TCPProtocol
a. IOBuffer *pInputBuffer = _pProtocol->GetInputBuffer(); //近点协议带有关于输入的IOBuffer _inputBuffer
以上实际调用TCPProtocol::GetInputBuffer()接口,然后返回TCPProtocol对象的成员 _inputBuffer
b. if (!pInputBuffer->ReadFromTCPFd(_inboundFd, _recvBufferSize, _ioAmount))
c. _pProtocol->SignalInputData(_ioAmount)
在函数内会调用_pNearProtocol->SignalInputData(_inputBuffer),对应调用BaseRTMPProtocol::SignalInputData()接口,在此函数内部进行输入数据的解析。

写:

a. pOutputBuffer = _pProtocol->GetOutputBuffer()
在函数内部调用_pNearProtocol->GetOutputBuffer(),实际调用BaseRTMPProtocol::GetOutputBuffer(),返回
BaseRTMPProtocol的成员IOBuffer _outputBuffer
b. pOutputBuffer->WriteToTCPFd(_outboundFd, _sendBufferSize, _ioAmount)

2. IOHandlerManager::DeleteDeadHandlers(); //
3. ProtocolManager::CleanupDeadProtocols(); //
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值