天天看點

Qt調用jrtplib實作單點傳播、多點傳播和廣播

jrtplib簡介可參考:http://blog.csdn.net/caoshangpa/article/details/51151942

RTP協定分析可參考:http://blog.csdn.net/caoshangpa/article/details/51149007

windows下編譯jrtplib可參考:http://blog.csdn.net/caoshangpa/article/details/51152541

linux下編譯jrtplib可參考:http://blog.csdn.net/caoshangpa/article/details/51416822

linux下交叉編譯jrtplib可參考:http://blog.csdn.net/caoshangpa/article/details/51416997

1.單點傳播

Qt調用jrtplib實作單點傳播、多點傳播和廣播

單點傳播是一種“一對一”模式,在單點傳播通信方式下,當一端發送資料報到一個指定的主機時,首先可能會引發ARP把目的IP位址映射為MAC位址,然而ARP就是基于廣播模式的實作。當以太網幀到達一個主機時,以太網接口便會把自己的MAC位址與幀中的MAC位址相比較,如果相符,以太網接口便會接收該幀,并按協定棧向上遞交,如果不想符,該幀将會忽略該幀。其他的以太網接口做同樣的操作,最後接收該幀的隻有一個主機。在此之後,然後以太網幀向上遞交到IP層目的主機會核對IP分組中的目的IP與本機IP(多主控端),符合,根據協定類型向上遞交到傳輸層相應的協定處理這即時單點傳播通信的過程。典型的TCP通信就是單點傳播模式的。

單點傳播在網絡中得到了廣泛的應用,網絡上絕大部分的資料都是以單點傳播的形式傳輸的,隻是一般網絡使用者不知道而已。例如,你在收發電子郵件、浏覽網頁時,必須與郵件伺服器、Web伺服器建立連接配接,此時使用的就是單點傳播資料傳輸方式。但是通常使用“點對點通信”(Point to Point)代替“單點傳播”,因為“單點傳播”一般與“多點傳播”和“廣播”相對應使用。

#include "crtpthread.h"
#include <QDebug>                                                                                                                                                                                 
CRtpThread::CRtpThread():
    m_runFlag(true)
{
#ifdef RECEIVER
    uint8_t destIP[]={192,168,1,168};
#else
    uint8_t destIP[]={192,168,1,183};
#endif
    initialRTP(destIP);
}

CRtpThread::~CRtpThread()
{
    m_session.BYEDestroy(RTPTime(10,0),0,0);
    m_runFlag=false;
#ifdef WIN32
    WSACleanup();
#endif // WIN32
}

void CRtpThread::run()
{
    while(m_runFlag)
    {
        usleep(1);
        m_session.BeginDataAccess();
        if (m_session.GotoFirstSourceWithData())
        {
            do
            {
                RTPPacket *pack;
                while ((pack = m_session.GetNextPacket()) != NULL)
                {
                    int recvSize = pack->GetPayloadLength();
                    uint8_t * recvData=pack->GetPayloadData();
                    dispatch(recvData, recvSize);
                    m_session.DeletePacket(pack);
                }
            } while (m_session.GotoNextSourceWithData());
        }

        m_session.EndDataAccess();

#ifndef RTP_SUPPORT_THREAD
        int status = m_session.Poll();
        if (status < 0)
        {
            qDebug()<< RTPGetErrorString(status).c_str();
        }
#endif
    }
}

void CRtpThread::dispatch(uchar *dataBuf, int dataLen)
{
   emit signalRtpData(dataBuf,dataLen);
#ifdef RECEIVER
   //将收到的資料轉發
   rtpSendData(dataBuf, dataLen);
#endif
}

void::CRtpThread::initialRTP(uint8_t *ip)
{
#ifdef WIN32
    WSADATA dat;
    WSAStartup(MAKEWORD(2,2),&dat);
#endif // WIN32
    //每秒發送10個樣本
    m_sessionparams.SetOwnTimestampUnit(1.0/10.0);
    //設定本地端口
    m_transparams.SetPortbase(27000);

    int status = m_session.Create(m_sessionparams,&m_transparams);

    if (status < 0)
    {
        qDebug()<< RTPGetErrorString(status).c_str();
    }
    //設定目的IP和端口
    RTPIPv4Address addr(ip,27000);
    status = m_session.AddDestination(addr);
    if (status < 0)
    {
       qDebug()<< RTPGetErrorString(status).c_str();
    }
    //這裡設定了預設值,發送的時候隻用指定資料和長度SendPacket((void *)dataBuf,dataLen)。
    //否則發送時需指定後三個參數,例如SendPacket((void *)dataBuf,dataLen,0,false,10)。
    m_session.SetDefaultPayloadType(0);
    m_session.SetDefaultMark(false);
    m_session.SetDefaultTimestampIncrement(10.0);
    m_session.SetMaximumPacketSize(65535);
}

void CRtpThread::rtpSendData(uchar *dataBuf, int dataLen)
{
    int status = m_session.SendPacket((void *)dataBuf,dataLen);
    if (status < 0)
    {
        qDebug() << RTPGetErrorString(status).c_str();
    }
}
           

通過注釋或放開.pro中的DEFINES +=RECEIVER來控制是發送端還是接收端,接收端會把收到的資料\n轉發給發送端。因為是單點傳播,是以在構造函數中需要指定兩個IP位址,然後調用initialRTP函數進行RTP的初始化。

發送端和接收端分别如下圖所示:

Qt調用jrtplib實作單點傳播、多點傳播和廣播
Qt調用jrtplib實作單點傳播、多點傳播和廣播

2.多點傳播

Qt調用jrtplib實作單點傳播、多點傳播和廣播

多點傳播是一種“一對一組”的模式,也就時加入同一個組的主機才會接收到資料,他綜合了單點傳播和廣播的優點,可以隻對特定的主機進行通信,其他的主機通信不受影響。多點傳播通常被指IP多點傳播,IP多點傳播是一種通過使用一個多點傳播位址将資料在同一時間以高效的方式發往處于TCP/IP網絡上的多個接收者的協定。但是對于IP多點傳播,擴容不容易。

“多點傳播”也可以稱為“多點傳播”,在網絡技術的應用并不是很多,網上視訊會議、網上視訊點播特别适合采用多點傳播方式。因為如果采用單點傳播方式,逐個節點傳輸,有多少個目标節點,就會有多少次傳送過程,這種方式顯然效率極低,是不可取的;如果采用不區分目标、全部發送的廣播方式,雖然一次可以傳送完資料,但是顯然達不到區分特定資料接收對象的目的。采用多點傳播方式,既可以實作一次傳送所有目标節點的資料,也可以達到隻對特定對象傳送資料的目的。IP網絡的多點傳播一般通過多點傳播IP位址來實作。多點傳播IP位址就是D類IP位址,即224.0.0.0至239.255.255.255之間的IP位址。Windows 2000中的DHCP管理器支援多點傳播IP位址的自動配置設定。

#include "crtpthread.h"
#include <QDebug>                                                                                                                                                                                 
CRtpThread::CRtpThread():
    m_runFlag(true)
{
    uint8_t destIP[]={224,212,118,99};
    initialRTP(destIP);
}

CRtpThread::~CRtpThread()
{
    m_session.BYEDestroy(RTPTime(10,0),0,0);
    m_runFlag=false;
#ifdef WIN32
    WSACleanup();
#endif // WIN32
}

void CRtpThread::run()
{
    while(m_runFlag)
    {
        usleep(1);
        m_session.BeginDataAccess();
        if (m_session.GotoFirstSourceWithData())
        {
            do
            {
                RTPPacket *pack;
                while ((pack = m_session.GetNextPacket()) != NULL)
                {
                    int recvSize = pack->GetPayloadLength();
                    uint8_t * recvData=pack->GetPayloadData();
                    dispatch(recvData, recvSize);
                    m_session.DeletePacket(pack);
                }
            } while (m_session.GotoNextSourceWithData());
        }

        m_session.EndDataAccess();

#ifndef RTP_SUPPORT_THREAD
        int status = m_session.Poll();
        if (status < 0)
        {
            qDebug()<< RTPGetErrorString(status).c_str();
        }
#endif
    }
}

void CRtpThread::dispatch(uchar *dataBuf, int dataLen)
{
   emit signalRtpData(dataBuf,dataLen);
}

void::CRtpThread::initialRTP(uint8_t *ip)
{
#ifdef WIN32
    WSADATA dat;
    WSAStartup(MAKEWORD(2,2),&dat);
#endif // WIN32
    //每秒發送10個樣本
    m_sessionparams.SetOwnTimestampUnit(1.0/10.0);
    //設定本地端口
    m_transparams.SetPortbase(27000);
    //設定網絡接口IP位址
//    uint8_t interfaceIP[]={114,212,118,99};
//    m_transparams.SetMulticastInterfaceIP(*interfaceIP);
    //設定多點傳播組資料的TTL值,範圍為0~255之間的任何值
    m_transparams.SetMulticastTTL(255);

    int status = m_session.Create(m_sessionparams,&m_transparams);
    if (status < 0)
    {
        qDebug()<< RTPGetErrorString(status).c_str();
    }
    //是否支援多點傳播
    bool iscast = m_session.SupportsMulticasting();
    if(!iscast)
    {
       m_session.Destroy();
       qDebug()<<"Do not support multicast";
       return;
    }
    //多點傳播位址
    RTPIPv4Address addr(ip,27000);
#ifdef RECEIVER
    //加入多點傳播
    status = m_session.JoinMulticastGroup(addr);
    if (status < 0)
    {
        qDebug()<< RTPGetErrorString(status).c_str();
    }
#else
    status = m_session.AddDestination(addr);
    if (status < 0)
    {
        qDebug()<< RTPGetErrorString(status).c_str();
    }
#endif
    //這裡設定了預設值,發送的時候隻用指定資料和長度SendPacket((void *)dataBuf,dataLen)。
    //否則發送時需指定後三個參數,例如SendPacket((void *)dataBuf,dataLen,0,false,10)。
    m_session.SetDefaultPayloadType(0);
    m_session.SetDefaultMark(false);
    m_session.SetDefaultTimestampIncrement(10.0);
    m_session.SetMaximumPacketSize(65535);  
}

void CRtpThread::rtpSendData(uchar *dataBuf, int dataLen)
{
    int status = m_session.SendPacket((void *)dataBuf,dataLen);
    if (status < 0)
    {
        qDebug() << RTPGetErrorString(status).c_str();
    }
}
           

對于發送端,需要将多點傳播位址當做目的位址加入會話;對于接收端,需要調用函數JoinMuticastGroup加入多點傳播組,這樣所有加入到多點傳播組的接收端都可以接收到發送端發送的資料。

發送端和接收端分别如下圖所示:

Qt調用jrtplib實作單點傳播、多點傳播和廣播
Qt調用jrtplib實作單點傳播、多點傳播和廣播

3.廣播

Qt調用jrtplib實作單點傳播、多點傳播和廣播

廣播時一種“一對所有”模式,在廣播模式下,該以太網幀被區域網路中所有的以太網接口接收,并向上遞交到傳輸層,如果指定的端口開啟并綁定相應的應用程序時,應用程序就會處理該資料報,如果端口沒有任何程序綁定,傳輸層就會丢棄該資料報。該主機并不會發送一個ICMP資料不可達的消息,否則會導緻廣播風暴。

廣播風暴就是網絡長時間被大量的廣播資料包所占用,正常的點對點通信無法正常進行,外在表現為網絡速度奇慢無比。出現廣播風暴的原因有很多,一塊有故障的網卡,就可能長時間向網絡上發送廣播包而導緻廣播風暴。“廣播”在網絡中的應用較多,如客戶機通過DHCP自動獲得IP位址的過程就是通過廣播來實作的。

#include "crtpthread.h"
#include <QDebug>                                                                                                                                                                                 
CRtpThread::CRtpThread():
    m_runFlag(true)
{
#ifdef RECEIVER
    uint8_t destIP[]={192,168,1,168};
#else
    uint8_t destIP[]={192,168,1,255};
#endif
    initialRTP(destIP);
}

CRtpThread::~CRtpThread()
{
    m_session.BYEDestroy(RTPTime(10,0),0,0);
    m_runFlag=false;
#ifdef WIN32
    WSACleanup();
#endif // WIN32
}

void CRtpThread::run()
{
    while(m_runFlag)
    {
        usleep(1);
        m_session.BeginDataAccess();
        if (m_session.GotoFirstSourceWithData())
        {
            do
            {
                RTPPacket *pack;
                while ((pack = m_session.GetNextPacket()) != NULL)
                {
                    int recvSize = pack->GetPayloadLength();
                    uint8_t * recvData=pack->GetPayloadData();
                    dispatch(recvData, recvSize);
                    m_session.DeletePacket(pack);
                }
            } while (m_session.GotoNextSourceWithData());
        }

        m_session.EndDataAccess();

#ifndef RTP_SUPPORT_THREAD
        int status = m_session.Poll();
        if (status < 0)
        {
            qDebug()<< RTPGetErrorString(status).c_str();
        }
#endif
    }
}

void CRtpThread::dispatch(uchar *dataBuf, int dataLen)
{
   emit signalRtpData(dataBuf,dataLen);
}

void::CRtpThread::initialRTP(uint8_t *ip)
{
#ifdef WIN32
    WSADATA dat;
    WSAStartup(MAKEWORD(2,2),&dat);
#endif // WIN32
    //每秒發送10個樣本
    m_sessionparams.SetOwnTimestampUnit(1.0/10.0);
    //設定本地端口
    m_transparams.SetPortbase(27000);

    int status = m_session.Create(m_sessionparams,&m_transparams);
    if (status < 0)
    {
        qDebug()<< RTPGetErrorString(status).c_str();
    }
    //設定目的IP和端口
    RTPIPv4Address addr(ip,27000);
    status = m_session.AddDestination(addr);
    if (status < 0)
    {
        qDebug()<< RTPGetErrorString(status).c_str();
    }
    //這裡設定了預設值,發送的時候隻用指定資料和長度SendPacket((void *)dataBuf,dataLen)。
    //否則發送時需指定後三個參數,例如SendPacket((void *)dataBuf,dataLen,0,false,10)。
    m_session.SetDefaultPayloadType(0);
    m_session.SetDefaultMark(false);
    m_session.SetDefaultTimestampIncrement(10.0);
    m_session.SetMaximumPacketSize(65535);  
}

void CRtpThread::rtpSendData(uchar *dataBuf, int dataLen)
{
    int status = m_session.SendPacket((void *)dataBuf,dataLen);
    if (status < 0)
    {
        qDebug() << RTPGetErrorString(status).c_str();
    }
}
           

RTP協定一般用于單點傳播和多點傳播,如果開發中有廣播的需求,廣播與單點傳播的唯一差別就是将發送端目标IP的最後字段設定為255,比如本例中的192.168.1.255,這樣的話該網段的接收端都能收到發送端發送的資料。

發送端和接收端運作效果與多點傳播相同。

使用jrtplib的一個具體例子: 基于RTP協定的H.264視訊傳輸系統:實作

參考連結:http://blog.csdn.net/wye213/article/details/9896547

參考連結:http://blog.csdn.net/maopig/article/details/6863253

參考連結:https://docs.oracle.com/cd/E38902_01/html/E38880/sockets-137.html

源碼連結:見http://blog.csdn.net/caoshangpa/article/details/52571183的評論

原創不易,轉載請标明出處:https://blog.csdn.net/caoshangpa/article/details/52571183

繼續閱讀