日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

RTMPdump(libRTMP) 源代码分析 5: 建立一个流媒体连接 (NetConnection部分)

發布時間:2024/2/28 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RTMPdump(libRTMP) 源代码分析 5: 建立一个流媒体连接 (NetConnection部分) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

=====================================================

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)??
  • {??
  • ????//Socket結構體??
  • ??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)??
  • ????{??
  • ????//加入地址信息??
  • ??????/*?使用SOCKS連接?*/??
  • ??????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
  • //sockaddr是Linux網絡編程的地址結構體一種,其定義如下:??
  • //struct?sockaddr{???
  • //??unsigned?short?sa_family;???
  • //??char?sa_data[14];??
  • //};???
  • //說明:sa_family:是地址家族,也稱作,協議族,一般都是“AF_xxx”的形式。通常大多用的是都是AF_INET。??
  • //??sa_data:是14字節協議地址。??
  • //有時不使用sockaddr,而使用sockaddr_in(多用在windows)(等價)??
  • //struct?sockaddr_in?{??
  • //??short?int?sin_family;??????????????/*?Address?family?*/??
  • //??unsigned?short?int?sin_port;???????/*?Port?number?*/??
  • //??struct?in_addr?sin_addr;???????????/*?Internet?address?*/??
  • //??unsigned?char?sin_zero[8];?????????/*?Same?size?as?struct?sockaddr?*/??
  • //};??
  • //union?{??
  • //???struct{??
  • //??????unsigned?char?s_b1,s_b2,s_b3,s_b4;??
  • //?????????}?S_un_b;??
  • //????struct?{??
  • //??????unsigned?short?s_w1,s_w2;??
  • //?????????}?S_un_w;??
  • //????unsigned?long?S_addr;??
  • //???}?S_un;??
  • //}?in_addr;??
  • //第0次連接,建立Socket連接??
  • 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;??
  • ??//創建一個Socket,并把Socket序號賦值給相應變量??
  • ??//-----------------??
  • ??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)??
  • ????{??
  • ??
  • ????//定義函數 int?connect?(int?sockfd,struct?sockaddr?*?serv_addr,int?addrlen);?  ??
  • ????//函數說明 connect()用來將參數sockfd?的Socket(剛剛創建)連至參數serv_addr???
  • ????//指定的網絡地址。參數addrlen為sockaddr的結構長度。???
  • ????//連接??
  • ????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?timeout?*/??
  • ??//超時??
  • ??{??
  • ????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
  • //第1次連接,從握手開始??
  • 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??
  • ????}??
  • ??//使用HTTP??
  • ??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__);??
  • ??//發送“connect”命令--------------??
  • ??//----------------??
  • ??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部分)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。