注:此前写了一些列的分析RTMPdump(libRTMP)源代码的文章,在此列一个列表:
RTMPdump 源代码分析 1: main()函数
RTMPDump(libRTMP)源代码分析 2:解析RTMP地址——RTMP_ParseURL()
RTMPdump(libRTMP) 源代码分析 3: AMF编码
RTMPdump(libRTMP)源代码分析 4: 连接第一步——握手(Hand Shake)
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里面的建立一个流媒体连接过程中的函数调用。
之前已经简单分析过流媒体链接的建立过程:
RTMP流媒体播放过程
而且分析过其函数调用过程:
RTMPDump源代码分析 0: 主要函数调用分析
在这里就不详细叙述了,其实主要是这两个函数:
RTMP_Connect()
RTMP_ConnectStream()
第一个函数用于建立RTMP中的NetConnection,第二个函数用于建立RTMP中的NetStream。一般是先调用第一个函数,然后调用第二个函数。
下面先来看看RTMP_Connect():
注意:贴上去的源代码是修改过的RTMPdump,我添加了输出信息的代码,形如:r->dlg->AppendCInfo("建立连接:第0次连接。开始建立Socket连接");改代码不影响程序运行,可忽略。
RTMP_Connect()
//连接
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()
//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()
//第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是一个开源命令行工具,用于从RTMP服务器上下载或播放流媒体内容。它支持RTMP、RTMPT、RTMPE、RTMPTE和RTMPS等多种协议变种。rtmpdump2.3是该工具的一个版本,可能包含了一些新特性或修复了某些已知...
对于想要深入了解网络流媒体技术或RTMP协议的开发者,rtmpdump源代码提供了一个很好的学习平台。你可以通过阅读和理解源代码,学习如何处理网络请求、解析复杂协议、实现流媒体的抓取和存储。同时,源代码也适用于...
在压缩包中的"rtmpdump-2.3"可能是rtmpdump的源代码或者编译好的二进制文件,用户可以进一步查看源码理解其工作原理,或者直接在Android设备上使用编译后的二进制文件进行流媒体操作。对于开发者来说,这为自定义...
rtmpdump是基于librtmp库构建的,主要功能包括连接RTMP服务器、发送控制命令、接收和保存流媒体数据。其命令行语法简洁,支持多种参数定制,如指定服务器地址、播放路径、输出文件等。 3. librtmp库: librtmp是...
librtmp 2.2是rtmpdump的一个关键组成部分,提供了对RTMP协议的底层支持。 **RTMP协议** RTMP是一种广泛应用于在线视频流传输的协议,由Adobe Systems开发。它允许内容提供商向用户实时传输音频、视频和其他数据。...
rtmpdump-2.4是一个强大的工具,尤其对需要抓取或回放RTMP流的开发者和爱好者来说。尽管需要手动编译,但其灵活性和实用性使其在Linux环境中具有很高的价值。记得在使用前了解RTMP协议和基本的命令行操作,这将有助...
rtmpdump是一个开源工具,主要用于从RTMP(Real-Time Messaging Protocol)流中捕获和下载媒体内容,如视频和音频。这个压缩包“rtmpdump.zip”包含了在Visual Studio环境中编译rtmpdump项目所需的所有关键文件,...
linrtmp则是rtmpdump在Linux环境下的一个变体或者特定版本,确保它能在Linux系统上运行。 rtmpdump-2.3是rtmpdump的特定版本,通常每个版本都会有针对前一版的改进和修复,比如增强稳定性、增加新功能或优化性能。...
总的来说,rtmpdump是一个强大的工具,它简化了与RTMP服务器交互的过程,特别是在需要抓取和分析流媒体内容时。通过使用你提供的压缩包,用户可以避免编译问题,直接在VC2010环境中使用rtmpdump,这对于开发者和网络...
rtmpdump是一个开源工具,由Alexander Zoller创建,用于从RTMP服务器中抓取、录制或者回放流媒体内容。它可以用于下载在线视频,帮助网络管理员进行故障排查,或者对RTMP服务器进行测试。rtmpdump支持多个RTMP变种,...
rtmpdump是一款强大的开源工具,主要用于从RTMP(Real-Time Messaging Protocol)服务器上抓取流媒体内容。RTMP是一种广泛用于在线视频传输的协议,由Adobe Systems开发。rtmpdump的2.4版本是我们讨论的重点。 这个...
rtmpdump的灵活性和易用性使其在直播流媒体领域具有广泛的用途,比如进行直播内容的备份、分析、调试和内容分发。同时,开发者也可以利用rtmpdump的源代码,学习如何实现RTMP协议的相关功能,为自己的项目提供支持。...
rtmpdump-v1.6.tar.gz是rtmpdump的一个特定版本,通过解压这个tar.gz压缩包,我们可以获取到rtmpdump的源代码和其他相关文件。在这个压缩包中,唯一列出的子文件名是"rtmpdump",这通常指的是rtmpdump的可执行程序...
例如,要记录一个RTMP流,命令可能如下: ``` rtmpdump -r rtmp://server/live/stream -o output.flv ``` 这将把`rtmp://server/live/stream`的流保存到`output.flv`文件中。 **总结** 通过VC6.0编译的RTMPDump....
5. **编程接口**:虽然RTMPDump是一个命令行工具,但也可以通过其提供的C库进行二次开发,将推流功能集成到你的应用程序中。这通常涉及到解析和构造RTMP协议的报文,以及处理网络I/O。 6. **安全性与授权**:在实际...
例如,你可以创建一个RTMPClient类,封装RTMP连接、发布流、播放流等功能,调用librtmp的API来实现: 1. 初始化RTMP连接:使用`RTMP_Alloc()`和`RTMP_Init()`初始化RTMP对象,然后通过`RTMP_SetupURL()`设置服务器...
rtmpdump是一个开源工具,主要用于从RTMP(Real Time Messaging Protocol)流中捕获和下载媒体数据,如视频和音频。这个压缩包“rtmpdump.zip”包含了使用C++编程语言编译通过的rtmpdump工程,适用于Visual Studio ...
rtmpdump 2.3 是一个开源工具,专为从RTMP(Real Time Messaging Protocol)流媒体服务器上抓取和下载点播视频文件而设计。它由Alexander Zerbe开发,广泛应用于网络视频内容的下载和分析。本文将详细探讨rtmpdump的...
rtmpdump 2.4 for vs2017是一个针对Visual Studio 2017编译环境优化的开源工具,主要用于处理RTMP(Real-Time Messaging Protocol)流媒体协议。RTMP是Adobe Systems开发的一种用于在互联网上传输音频、视频和数据的...
开发者可以利用rtmpdump来分析RTMP流量,或者在没有原始流源的情况下记录和播放RTMP内容。此外,rtmpdump也可以用来下载RTMP流,例如从直播网站获取视频内容。 4. RTMP客户端:是指能够连接到RTMP服务器并接收流...