=====================================================
RTMPdump(libRTMP) 源代碼分析系列文章:
RTMPdump 源代碼分析?1: main()函數
RTMPDump (libRTMP) 源代碼分析2:解析RTMP地址——RTMP_ParseURL()
RTMPdump (libRTMP) 源代碼分析3: AMF編碼
RTMPdump (libRTMP) 源代碼分析4: 連接第一步——握手 (HandShake)
RTMPdump (libRTMP) 源代碼分析5: 建立一個流媒體連接 ?(NetConnection部分)
RTMPdump (libRTMP) 源代碼分析6: 建立一個流媒體連接 ?(NetStream部分 1)
RTMPdump (libRTMP) 源代碼分析7: 建立一個流媒體連接 ?(NetStream部分 2)
RTMPdump (libRTMP) 源代碼分析8: 發送消息 (Message)
RTMPdump (libRTMP) 源代碼分析9: 接收消息 (Message) ?(接收視音頻數據)
RTMPdump (libRTMP) 源代碼分析10: 處理各種消息 (Message)
=====================================================
函數調用結構圖
RTMPDump (libRTMP)的整體的函數調用結構圖如下圖所示。
單擊查看大圖
詳細分析
本篇文章分析一下RTMPdump里面的建立一個流媒體連接過程中的函數調用。
之前已經簡單分析過流媒體鏈接的建立過程:
RTMP流媒體播放過程
而且分析過其函數調用過程:
RTMPDump源代碼分析 0: 主要函數調用分析
在這里就不詳細敘述了,其實主要是這兩個函數:
RTMP_Connect()
RTMP_ConnectStream()
第一個函數用于建立RTMP中的NetConnection,第二個函數用于建立RTMP中的NetStream。一般是先調用第一個函數,然后調用第二個函數。
下面先來看看RTMP_Connect():
注意:貼上去的源代碼是修改過的RTMPdump,我添加了輸出信息的代碼,形如:r->dlg->AppendCInfo("建立連接:第0次連接。開始建立Socket連接");改代碼不影響程序運行,可忽略。
RTMP_Connect()
[cpp]?view plaincopy
?? int?? RTMP_Connect(RTMP?*r,?RTMPPacket?*cp)?? {?? ?????? ??struct?sockaddr_in?service;?? ??if?(!r->Link.hostname.av_len)?? ????return?FALSE;?? ?? ??memset(&service,?0,?sizeof(struct?sockaddr_in));?? ??service.sin_family?=?AF_INET;?? ?? ??if?(r->Link.socksport)?? ????{?? ?????? ???????? ??????if?(!add_addr_info(&service,?&r->Link.sockshost,?r->Link.socksport))?? ????return?FALSE;?? ????}?? ??else?? ????{?? ???????? ??????if?(!add_addr_info(&service,?&r->Link.hostname,?r->Link.port))?? ????return?FALSE;?? ????}?? ???? ??r->dlg->AppendCInfo("建立連接:第0次連接。開始建立Socket連接");?? ???? ??if?(!RTMP_Connect0(r,?(struct?sockaddr?*)&service)){?? ????r->dlg->AppendCInfo("建立連接:第0次連接。建立Socket連接失敗");?? ????return?FALSE;?? ??}?? ???? ??r->dlg->AppendCInfo("建立連接:第0次連接。建立Socket連接成功");?? ???? ??r->m_bSendCounter?=?TRUE;?? ?? ??return?RTMP_Connect1(r,?cp);?? }??
我們可以看出調用了兩個函數RTMP_Connect0()以及RTMP_Connect1()。按照按先后順序看看吧:
RTMP_Connect0()
[cpp]?view plaincopy
?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? int?? RTMP_Connect0(RTMP?*r,?struct?sockaddr?*?service)?? {?? ??int?on?=?1;?? ??r->m_sb.sb_timedout?=?FALSE;?? ??r->m_pausing?=?0;?? ??r->m_fDuration?=?0.0;?? ???? ???? ??r->dlg->AppendCInfo("建立連接:第0次連接。create一個Socket");?? ???? ??r->m_sb.sb_socket?=?socket(AF_INET,?SOCK_STREAM,?IPPROTO_TCP);?? ??if?(r->m_sb.sb_socket?!=?-1)?? ????{?? ?? ?????? ?????? ?????? ?????? ????RTMP_LogPrintf("建立Socket連接!\n");?? ?????? ????r->dlg->AppendCInfo("建立連接:第0次連接。connect該Socket");?? ?????? ??????if?(connect(r->m_sb.sb_socket,?service,?sizeof(struct?sockaddr))?<?0)?? ????{?? ?????????? ????????r->dlg->AppendCInfo("建立連接:第0次連接。connect該Socket失敗");?? ?????????? ??????int?err?=?GetSockError();?? ??????RTMP_Log(RTMP_LOGERROR,?"%s,?failed?to?connect?socket.?%d?(%s)",?? ??????????__FUNCTION__,?err,?strerror(err));?? ??????RTMP_Close(r);?? ??????return?FALSE;?? ????}?? ???????? ??????r->dlg->AppendCInfo("建立連接:第0次連接。connect該Socket成功");?? ???????? ???????? ??????if?(r->Link.socksport)?? ????{?? ??????RTMP_Log(RTMP_LOGDEBUG,?"%s?...?SOCKS?negotiation",?__FUNCTION__);?? ???????? ??????if?(!SocksNegotiate(r))?? ????????{?? ??????????RTMP_Log(RTMP_LOGERROR,?"%s,?SOCKS?negotiation?failed.",?__FUNCTION__);?? ??????????RTMP_Close(r);?? ??????????return?FALSE;?? ????????}?? ????}?? ????}?? ??else?? ????{?? ??????RTMP_Log(RTMP_LOGERROR,?"%s,?failed?to?create?socket.?Error:?%d",?__FUNCTION__,?? ??????GetSockError());?? ??????return?FALSE;?? ????}?? ?? ???? ???? ??{?? ????SET_RCVTIMEO(tv,?r->Link.timeout);?? ????if?(setsockopt?? ????????(r->m_sb.sb_socket,?SOL_SOCKET,?SO_RCVTIMEO,?(char?*)&tv,?sizeof(tv)))?? ??????{?? ????????RTMP_Log(RTMP_LOGERROR,?"%s,?Setting?socket?timeout?to?%ds?failed!",?? ????????__FUNCTION__,?r->Link.timeout);?? ??????}?? ??}?? ?? ??setsockopt(r->m_sb.sb_socket,?IPPROTO_TCP,?TCP_NODELAY,?(char?*)?&on,?sizeof(on));?? ?? ??return?TRUE;?? }??
可見RTMP_Connect0()主要用于建立Socket連接,并未開始真正的建立RTMP連接。
再來看看RTMP_Connect1(),這是真正建立RTMP連接的函數:
RTMP_Connect1()
[cpp]?view plaincopy
?? int?? RTMP_Connect1(RTMP?*r,?RTMPPacket?*cp)?? {?? ??if?(r->Link.protocol?&?RTMP_FEATURE_SSL)?? ????{?? #if?defined(CRYPTO)?&&?!defined(NO_SSL)?? ??????TLS_client(RTMP_TLS_ctx,?r->m_sb.sb_ssl);?? ??????TLS_setfd((SSL?*)r->m_sb.sb_ssl,?r->m_sb.sb_socket);?? ??????if?(TLS_connect((SSL?*)r->m_sb.sb_ssl)?<?0)?? ????{?? ??????RTMP_Log(RTMP_LOGERROR,?"%s,?TLS_Connect?failed",?__FUNCTION__);?? ??????RTMP_Close(r);?? ??????return?FALSE;?? ????}?? #else?? ??????RTMP_Log(RTMP_LOGERROR,?"%s,?no?SSL/TLS?support",?__FUNCTION__);?? ??????RTMP_Close(r);?? ??????return?FALSE;?? ?? #endif?? ????}?? ???? ??if?(r->Link.protocol?&?RTMP_FEATURE_HTTP)?? ????{?? ??????r->m_msgCounter?=?1;?? ??????r->m_clientID.av_val?=?NULL;?? ??????r->m_clientID.av_len?=?0;?? ??????HTTP_Post(r,?RTMPT_OPEN,?"",?1);?? ??????HTTP_read(r,?1);?? ??????r->m_msgCounter?=?0;?? ????}?? ??RTMP_Log(RTMP_LOGDEBUG,?"%s,?...?connected,?handshaking",?__FUNCTION__);?? ???? ??r->dlg->AppendCInfo("建立連接:第1次連接。開始握手(HandShake)");?? ???? ??RTMP_LogPrintf("開始握手(HandShake)!\n");?? ??if?(!HandShake(r,?TRUE))?? ????{?? ?????????? ????????r->dlg->AppendCInfo("建立連接:第1次連接。握手(HandShake)失敗!");?? ?????????? ??????RTMP_Log(RTMP_LOGERROR,?"%s,?handshake?failed.",?__FUNCTION__);?? ??????RTMP_Close(r);?? ??????return?FALSE;?? ????}?? ???? ??r->dlg->AppendCInfo("建立連接:第1次連接。握手(HandShake)成功");?? ???? ??RTMP_LogPrintf("握手(HandShake)完畢!\n");?? ??RTMP_Log(RTMP_LOGDEBUG,?"%s,?handshaked",?__FUNCTION__);?? ???? ???? ??r->dlg->AppendCInfo("建立連接:第1次連接。開始建立網絡連接(NetConnection)");?? ???? ??RTMP_LogPrintf("開始建立網絡連接(NetConnection)!\n");?? ???? ??r->dlg->AppendCInfo("發送數據。消息?命令?(typeID=20)?(Connect)。");?? ???? ??if?(!SendConnectPacket(r,?cp))?? ????{?? ?????????? ????????r->dlg->AppendCInfo("建立連接:第1次連接。建立網絡連接(NetConnection)失敗!");?? ?????????? ??????RTMP_Log(RTMP_LOGERROR,?"%s,?RTMP?connect?failed.",?__FUNCTION__);?? ??????RTMP_Close(r);?? ??????return?FALSE;?? ????}?? ???? ??r->dlg->AppendCInfo("建立連接:第1次連接。建立網絡連接(NetConnection)成功");?? ???? ??RTMP_LogPrintf("命令消息“Connect”發送完畢!\n");?? ??return?TRUE;?? }??
該函數做了以下事情:
HandShake()完成握手,之前已經分析過:RTMPdump 源代碼分析 4: 連接第一步——握手(Hand Shake)
SendConnectPacket()發送包含“connect”命令的數據報,用于開始建立RTMP連接。具體該函數是怎么調用的,以后有機會再進行分析。
至此RTMP_Connect()分析完畢。
rtmpdump源代碼(Linux):http://download.csdn.net/detail/leixiaohua1020/6376561
rtmpdump源代碼(VC 2005 工程):http://download.csdn.net/detail/leixiaohua1020/6563163
總結
以上是生活随笔為你收集整理的RTMPdump(libRTMP) 源代码分析 5: 建立一个流媒体连接 (NetConnection部分)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。