OpenRTMFP/Cumulus Primer(5)CumulusServer啟動流程分析(續)
OpenRTMFP/Cumulus Primer(5)CumulusServer啟動流程分析(續)
- 作者:柳大·Poechant(鍾超)
- 部落格:Blog.CSDN.net/Poechant
- 郵箱:zhongchao.ustc#gmail.com (# -> @)
- 日期:April 14th, 2012
1 CumulusServer 是 ServerApplication 的子類
ServerApplication 對其子類有如下要求:
- Subsystems must be registered in the constructor.
- All non-trivial initializations must be made in the initialize() method.
- At the end of the main() method, waitForTerminationRequest() should be called.
2 ServerApplication 是 Application 的子類
Application 對其子類的要求是,如下這些成員函式必須被覆蓋:
- initialize() (the one-argument, protected variant):上一篇已介紹過。
- uninitialize():下面會介紹,Application 的 run() 函式會在呼叫 main() 函式後呼叫 uninitialize() 函式。
- reinitialize()
- defineOptions():定義命令列啟動選項。
- handleOption():響應相應的命令列選項。
- main():
3 反初始化
CumulusServer
是繼承ServerApplication
的,ServerApplication
是繼承Application
的。Application
的run()
函式會先呼叫initialize()
,然後呼叫main()
,最後呼叫uninitialize
。最後這個反初始化過程,在CumulusServer
就是直接呼叫父類的uninitialize
函式。
void uninitialize() {
ServerApplication::uninitialize();
}
4 命令列選項設定
CumulusServer
的命令列選項有:log
(l)、dump
(d)、cirrus
(c)、middle
(m)、help
(h)。
void defineOptions(OptionSet& options) {
ServerApplication::defineOptions(options);
設定日誌級別(0 - 8,預設是 6,表示 info 級別)。
options.addOption(
Option("log", "l", "Log level argument, must be beetween 0 and 8 : \
nothing, fatal, critic, error, warn, note, info, debug, trace. \
Default value is 6 (info), all logs until info level are displayed.")
.required(false)
.argument("level")
.repeatable(false));
其他一些選項:
options.addOption(
Option("dump", "d", "Enables packet traces in logs. Optional arguments \
are 'middle' or 'all' respectively to displays just middle packet \
process or all packet process. If no argument is given, just outside \
packet process will be dumped.",false,"middle|all",false)
.repeatable(false));
options.addOption(
Option("cirrus", "c", "Cirrus address to activate a 'man-in-the-middle' \
developer mode in bypassing flash packets to the official cirrus \
server of your choice, it's a instable mode to help Cumulus developers, \
\"p2p.rtmfp.net:10000\" for example. By adding the 'dump' argument, \
you will able to display Cirrus/Flash packet exchange in your logs \
(see 'dump' argument).",false,"address",true)
.repeatable(false));
options.addOption(
Option("middle", "m","Enables a 'man-in-the-middle' developer mode \
between two peers. It's a instable mode to help Cumulus developers. \
By adding the 'dump' argument, you will able to display Flash/Flash \
packet exchange in your logs (see 'dump' argument).")
.repeatable(false));
顯示幫助資訊的選項:
options.addOption(
Option("help", "h", "Displays help information about command-line usage.")
.required(false)
.repeatable(false));
}
OptionSet
是Poco::Util::OptionSet
,呼叫addOption
可以向其中增加選項Option
。其中required
和repeatable
表示:
- Sets whether the option is required (flag == true) or optional (flag == false).
- Returns true if the option can be specified more than once, or false if at most once.
當需要顯示幫助資訊時,呼叫如下函式:
void displayHelp() {
HelpFormatter helpFormatter(options());
helpFormatter.setCommand(commandName());
helpFormatter.setUsage("OPTIONS");
helpFormatter.setHeader("CumulusServer, open source RTMFP server");
helpFormatter.format(cout);
}
- setCommand(): Sets the command name.
- setUsage(): Sets the usage string.
- setHeader(): Sets the header string.
- format(): Writes the formatted help text to the given stream.
5 處理命令列選項
引數是選項名和選項值。
void handleOption(const std::string& name, const std::string& value) {
ServerApplication::handleOption(name, value);
如果選項是幫助:
if (name == "help")
_helpRequested = true;
如果是cirrus
,即該服務的 IP 和埠號,Poco::URI 中有協議名(Scheme)、IP 地址(Host)、埠號(Port)、查詢串(Query)等等。
else if (name == "cirrus") {
try {
URI uri("rtmfp://"+value);
_pCirrus = new SocketAddress(uri.getHost(),uri.getPort());
NOTE("Mode 'man in the middle' : the exchange will bypass to '%s'",value.c_str());
} catch(Exception& ex) {
ERROR("Mode 'man in the middle' error : %s",ex.message().c_str());
}
如果選項是dump
日誌:
} else if (name == "dump") {
if(value == "all")
Logs::SetDump(Logs::ALL);
else if(value == "middle")
Logs::SetDump(Logs::MIDDLE);
else
Logs::SetDump(Logs::EXTERNAL);
如果選項是middle
:
} else if (name == "middle")
_middle = true;
如果選項是log
,表示設定日誌級別:
else if (name == "log")
Logs::SetLevel(atoi(value.c_str()));
}
6 Dump logs
先加一個作用域鎖,然後再向日誌流寫資料。
void dumpHandler(const UInt8* data,UInt32 size) {
ScopedLock<FastMutex> lock(_logMutex);
cout.write((const char*)data, size);
_logStream.write((const char*)data,size);
manageLogFile();
}
呼叫 manageLogFile,主要做一些日誌大小超出限制的處理。
void manageLogFile() {
先判斷是否超過日誌檔案的大小上線,LOG_SIZE
是1000000
位元組(即約 1 MB)。
if(_pLogFile->getSize() > LOG_SIZE) {
_logStream.close();
int num = 10;
開啟新日誌檔案:
File file(_logPath + "10");
如果該檔案已經存在,則先刪除:
if (file.exists())
file.remove();
while (--num >= 0) {
file = _logPath + NumberFormatter::format(num);
if (file.exists())
file.renameTo(_logPath + NumberFormatter::format(num + 1));
}
_logStream.open(_pLogFile->path(), ios::in | ios::ate);
}
}
7 停止執行
CumulusServer
繼承了ApplicationKiller
,該類中有純虛擬函式kill()
需要被實現,於是有:
void kill() {
terminate();
}
ApplicationKiller
的定義在ApplicationKiller.h
中,如下:
class ApplicationKiller {
public:
ApplicationKiller(){}
virtual ~ApplicationKiller(){}
virtual void kill()=0;
};
8 載入配置
在initialize()
函式中呼叫,上一篇已提到過。
void loadConfiguration(const string& path) {
try {
ServerApplication::loadConfiguration(path);
} catch(...) {
}
}
9 處理日誌
void logHandler(Thread::TID threadId,
const std::string& threadName,
Priority priority,
const char *filePath,
long line,
const char *text) {
作用域鎖:
ScopedLock<FastMutex> lock(_logMutex);
Path path(filePath);
string file;
if (path.getExtension() == "lua")
file += path.directory(path.depth()-1) + "/";
如果是命令列互動模式(即不是 daemon 模式):
if (_isInteractive)
printf("%s %s[%ld] %s\n",
g_logPriorities[priority - 1],
(file + path.getBaseName()).c_str(),
line,
text);
向日志流輸出一句日誌:
_logStream << DateTimeFormatter::format(LocalDateTime(),"%d/%m %H:%M:%S.%c ")
<< g_logPriorities[priority-1]
<< '\t' << threadName
<< '(' << threadId << ")\t"
<< (file + path.getFileName())
<< '[' << line << "] "
<< text << std::endl;
_logStream.flush();
日誌檔案的善後處理(主要處理檔案大小限制可能產生的問題):
manageLogFile();
}
-
轉載請註明來自柳大的CSDN部落格:Blog.CSDN.net/Poechant
-
相關文章
- OpenRTMFP/Cumulus Primer(5)CumulusServer啟動流程分析(續1)Server
- OpenRTMFP/Cumulus Primer(6)CumulusServer啟動流程分析(續2)Server
- OpenRTMFP/Cumulus Primer(7)CumulusServer啟動流程分析(續3)Server
- OpenRTMFP/Cumulus Primer(7)CumulusServer 啟動流程分析(續3)Server
- OpenRTMFP/Cumulus Primer(4)CumulusServer啟動流程分析Server
- OpenRTMFP/Cumulus Primer(8)CumulusServer主程式主迴圈分析Server
- OpenRTMFP/Cumulus Primer(1)入門介紹與部署CumulusServerServer
- OpenRTMFP/Cumulus Primer(2)用Lua編寫HelloWorld應用擴充套件CumulusServer套件Server
- OpenRTMFP/Cumulus Primer(18)AMF解析之AMFReader(續2)
- OpenRTMFP/Cumulus Primer(17)AMF解析之AMFReader(續1)
- OpenRTMFP/Cumulus Primer(16)AMF解析之AMFReader
- OpenRTMFP/Cumulus Primer(14)AMF解析之PacketReader/Writer
- OpenRTMFP/Cumulus Primer(22)執行緒邏輯分析之一:RTMFPServer執行緒的啟動和等待執行緒Server
- OpenRTMFP/Cumulus Primer(9)AMF解析之BinaryReader/Writer
- OpenRTMFP/Cumulus Primer(21)經由伺服器的釋出/訂閱流程的關鍵點伺服器
- OpenRTMFP/Cumulus Primer(15)AMF解析之資料型別定義資料型別
- OpenRTMFP/Cumulus Primer(9)AMF 處理方式解析——BinaryReader/Writer
- OpenRTMFP/Cumulus Primer(13)IO管理之區域性記憶體片記憶體
- OpenRTMFP/Cumulus Primer(23)執行緒邏輯分析之二:RTMFPManager對RTMFPServer的影響執行緒Server
- OpenRTMFP/Cumulus Primer(19)獨立使用CumulusLib時的執行緒安全Bug執行緒
- Activity啟動流程分析
- activity 啟動流程分析
- FlutterApp啟動流程分析FlutterAPP
- nodejs啟動流程分析NodeJS
- Flutter啟動流程原始碼分析Flutter原始碼
- Linux:uboot啟動流程分析Linuxboot
- apiserver原始碼分析——啟動流程APIServer原始碼
- Activity啟動流程原始碼分析原始碼
- Android應用啟動流程分析Android
- Flutter系列三:Flutter啟動流程分析Flutter
- Tomcat原始碼分析--啟動流程Tomcat原始碼
- JobTracker啟動流程原始碼級分析原始碼
- 以太坊原始碼分析(39)geth啟動流程分析原始碼
- Android Activity啟動流程原始碼分析Android原始碼
- SpringBoot啟動流程分析原理(一)Spring Boot
- Android原始碼分析:Activity啟動流程Android原始碼
- [譯]Android Application 啟動流程分析AndroidAPP
- Android 7.0 應用啟動流程分析Android