ZLMediaKit RTSP专题:RTP over UDP/TCP/HTTP/组播四种传输方式

ZLMediaKit RTSP专题:RTP over UDP/TCP/HTTP/组播四种传输方式

【免费下载链接】ZLMediaKit 基于C++11的WebRTC/RTSP/RTMP/HTTP/HLS/HTTP-FLV/WebSocket-FLV/HTTP-TS/HTTP-fMP4/WebSocket-TS/WebSocket-fMP4/GB28181/SRT服务器和客户端框架。 【免费下载链接】ZLMediaKit 项目地址: https://gitcode.com/GitHub_Trending/zl/ZLMediaKit

引言

在流媒体开发中,RTSP(Real Time Streaming Protocol,实时流传输协议)作为经典的控制协议,其RTP(Real-time Transport Protocol,实时传输协议)数据传输方式的选择直接影响着系统的性能和兼容性。ZLMediaKit作为高性能的流媒体服务器框架,全面支持RTP over UDP、TCP、HTTP和组播四种传输方式,为不同场景提供了灵活的解决方案。

你是否遇到过以下痛点:

  • 网络限制导致UDP传输失败?
  • 网络质量差时TCP传输延迟高?
  • 需要大规模分发时单播效率低下?
  • 移动网络环境下连接稳定性差?

本文将深入解析ZLMediaKit中RTSP协议的四种RTP传输方式,通过技术原理、实现细节和实战案例,帮助你选择最适合的传输方案。

四种传输方式概述

ZLMediaKit支持的四种RTP传输方式对比如下:

传输方式协议特点适用场景优势劣势
RTP over UDP独立UDP端口传输局域网、高质量网络低延迟、高效率网络穿透差
RTP over TCPRTSP信令通道传输公网、不稳定网络网络友好、可靠延迟较高
RTP over HTTPHTTP协议伪装严格网络环境最强穿透能力实现复杂
RTP over 组播共享组播端口大规模分发带宽利用率高需要网络支持

RTP over UDP:经典高效传输

技术原理

RTP over UDP是RTSP协议的标准传输方式,使用独立的UDP端口进行音视频数据传输:

mermaid

ZLMediaKit实现

在ZLMediaKit中,UDP传输的核心实现在RtspSession::handleReq_Setup方法中:

case Rtsp::RTP_UDP: {
    std::pair<Socket::Ptr, Socket::Ptr> pr = std::make_pair(createSocket(),createSocket());
    try {
        makeSockPair(pr, get_local_ip());
    } catch (std::exception &ex) {
        send_NotAcceptable();
        throw SockException(Err_shutdown, ex.what());
    }

    _rtp_socks[trackIdx] = pr.first;
    _rtcp_socks[trackIdx] = pr.second;
    
    // 设置客户端端口信息
    string strClientPort = findSubString(parser["Transport"].data(), "client_port=", NULL);
    uint16_t ui16RtpPort = atoi(findSubString(strClientPort.data(), NULL, "-").data());
    uint16_t ui16RtcpPort = atoi(findSubString(strClientPort.data(), "-", NULL).data());

    // 绑定对端地址
    auto peerAddr = SockUtil::make_sockaddr(get_peer_ip().data(), ui16RtpPort);
    pr.first->bindPeerAddr((struct sockaddr *) (&peerAddr), 0, true);
    
    peerAddr = SockUtil::make_sockaddr(get_peer_ip().data(), ui16RtcpPort);
    pr.second->bindPeerAddr((struct sockaddr *) (&peerAddr), 0, true);
}

适用场景

  • 局域网内高质量网络环境
  • 对延迟敏感的音视频应用
  • 无需网络穿透的内部系统

RTP over TCP:可靠传输方案

技术原理

RTP over TCP将RTP/RTCP数据通过RTSP信令的TCP连接进行传输,使用交织(interleaved)方式区分不同的数据通道:

mermaid

ZLMediaKit实现

TCP传输的核心代码同样在handleReq_Setup方法中:

case Rtsp::RTP_TCP: {
    if (_push_src) {
        // 推流时interleaved由客户端决定
        auto key_values = Parser::parseArgs(parser["Transport"], ";", "=");
        int interleaved_rtp = -1, interleaved_rtcp = -1;
        if (2 == sscanf(key_values["interleaved"].data(), "%d-%d", &interleaved_rtp, &interleaved_rtcp)) {
            trackRef->_interleaved = interleaved_rtp;
        }
    } else {
        // 播放时interleaved由服务器决定
        trackRef->_interleaved = 2 * trackRef->_type;
    }
    
    // 启用RTP接收
    RtspSplitter::enableRecvRtp(true);
}

数据接收处理在onRtpPacket方法中:

void RtspSession::onRtpPacket(const char *data, size_t len) {
    uint8_t interleaved = data[1];
    if (interleaved % 2 == 0) {
        // RTP数据包
        RtpHeader *header = (RtpHeader *)(data + RtpPacket::kRtpTcpHeaderSize);
        auto track_idx = getTrackIndexByPT(header->pt);
        handleOneRtp(track_idx, _sdp_track[track_idx]->_type, 
                    _sdp_track[track_idx]->_samplerate, 
                    (uint8_t *) data + RtpPacket::kRtpTcpHeaderSize, 
                    len - RtpPacket::kRtpTcpHeaderSize);
    } else {
        // RTCP数据包
        auto track_idx = getTrackIndexByInterleaved(interleaved - 1);
        onRtcpPacket(track_idx, _sdp_track[track_idx], 
                    data + RtpPacket::kRtpTcpHeaderSize, 
                    len - RtpPacket::kRtpTcpHeaderSize);
    }
}

适用场景

  • 需要网络穿透的公网环境
  • 网络质量不稳定的移动网络
  • 对可靠性要求高于延迟的场景

RTP over HTTP:网络穿透利器

技术原理

RTP over HTTP是一种巧妙的网络穿透方案,将RTSP协议伪装成HTTP协议:

mermaid

ZLMediaKit实现

HTTP传输的处理在handleReq_GethandleReq_Post方法中:

void RtspSession::handleReq_Get(const Parser &parser) {
    // 获取x-sessioncookie
    _http_x_sessioncookie = parser["x-sessioncookie"];
    if (_http_x_sessioncookie.empty()) {
        _http_x_sessioncookie = makeRandStr(12);
    }
    
    // 注册为HTTP Getter
    lock_guard<recursive_mutex> lock(g_mtxGetter);
    g_mapGetter[_http_x_sessioncookie] = static_pointer_cast<RtspSession>(shared_from_this());
    
    // 设置接收回调
    _on_recv = [](const Buffer::Ptr &buf) {
        // 处理POSTer转发过来的数据
    };
}

void RtspSession::handleReq_Post(const Parser &parser) {
    string sessioncookie = parser["x-sessioncookie"];
    weak_ptr<RtspSession> getter;
    
    {
        lock_guard<recursive_mutex> lock(g_mtxGetter);
        auto it = g_mapGetter.find(sessioncookie);
        if (it != g_mapGetter.end()) {
            getter = it->second;
        }
    }
    
    if (getter.lock()) {
        // 将POST数据转发给对应的Getter处理
        getter.lock()->onRecv(buf);
    }
}

适用场景

  • 企业网络严格限制的网络环境
  • 只能通过80/443端口通信的场景
  • 需要最大程度兼容性的跨网络应用

RTP over 组播:大规模分发方案

技术原理

组播传输允许多个客户端共享同一个组播地址和端口接收数据,极大节省服务器带宽:

mermaid

ZLMediaKit实现

组播功能通过RtpMultiCaster类实现:

case Rtsp::RTP_MULTICAST: {
    if(!_multicaster){
        _multicaster = RtpMultiCaster::get(*this, get_local_ip(), _media_info, 
                                         _multicast_ip, _multicast_video_port, 
                                         _multicast_audio_port);
        if (!_multicaster) {
            send_NotAcceptable();
            throw SockException(Err_shutdown, "can not get a available udp multicast socket");
        }
    }
    
    int iSrvPort = _multicaster->getMultiCasterPort(trackRef->_type);
    // 设置RTCP共享端口
    auto pSockRtcp = UDPServer::Instance().getSock(*this, get_local_ip().data(), 
                                                  2 * trackIdx + 1, iSrvPort + 1);
}

组播地址管理通过MultiCastAddressMaker单例类:

class MultiCastAddressMaker {
public:
    static MultiCastAddressMaker& Instance();
    std::shared_ptr<uint32_t> obtain();
    void release(std::shared_ptr<uint32_t> addr);
    static std::string toString(uint32_t addr);
};

适用场景

  • 大规模直播分发系统
  • 企业内部视频会议
  • IPTV等广播式应用

实战配置指南

服务器端配置

在ZLMediaKit的配置文件中,可以设置默认的传输方式:

[rtsp]
# 传输方式限制: -1-不限制 0-TCP 1-UDP 2-组播
rtpTransportType=-1

# 组播相关配置
[multicast]
# 组播UDP TTL
udpTTL=64

客户端请求示例

不同传输方式的SETUP请求示例:

UDP传输:

SETUP rtsp://example.com/stream/track1 RTSP/1.0
CSeq: 3
Transport: RTP/AVP/UDP;unicast;client_port=5000-5001

TCP传输:

SETUP rtsp://example.com/stream/track1 RTSP/1.0
CSeq: 3
Transport: RTP/AVP/TCP;unicast;interleaved=0-1

组播传输:

SETUP rtsp://example.com/stream/track1 RTSP/1.0
CSeq: 3
Transport: RTP/AVP;multicast

HTTP传输:

GET /stream RTSP/1.0
x-sessioncookie: abcdef123456

性能优化建议

  1. UDP模式:适合局域网,设置合理的socket buffer大小
  2. TCP模式:启用TCP_NODELAY减少延迟
  3. 组播模式:合理设置TTL值,控制组播范围
  4. HTTP模式:优化Base64编解码性能

故障排查与调试

常见问题解决

问题现象可能原因解决方案
UDP连接失败网络阻挡切换TCP或HTTP模式
TCP延迟高网络拥塞优化网络或使用UDP
组播不工作网络不支持检查路由器组播配置
HTTP模式异常Cookie不匹配检查x-sessioncookie设置

调试技巧

使用Wireshark抓包分析:

  • 过滤条件:rtsp || http
  • 关注SETUP请求的Transport字段

【免费下载链接】ZLMediaKit 基于C++11的WebRTC/RTSP/RTMP/HTTP/HLS/HTTP-FLV/WebSocket-FLV/HTTP-TS/HTTP-fMP4/WebSocket-TS/WebSocket-fMP4/GB28181/SRT服务器和客户端框架。 【免费下载链接】ZLMediaKit 项目地址: https://gitcode.com/GitHub_Trending/zl/ZLMediaKit

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值