一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

jrtplib介紹

 royy 2011-05-20

一、流媒體簡介

隨著Internet 的日益普及,在網絡上傳輸的數據已經不再局限于文字和圖形,而是逐漸向聲音和視頻等多媒體格式過渡。目前在網絡上傳輸音頻/視頻(Audio /Video,簡稱A/V)等多媒體文件時,基本上只有下載和流式傳輸兩種選擇。通常說來,A/V文件占據的存儲空間都比較大,在帶寬受限的網絡環(huán)境中下 載可能要耗費數分鐘甚至數小時,所以這種處理方法的延遲很大。如果換用流式傳輸的話,聲音、影像、動畫等多媒體文件將由專門的流媒體服務器負責向用戶連 續(xù)、實時地發(fā)送,這樣用戶可以不必等到整個文件全部下載完畢,而只需要經過幾秒鐘的啟動延時就可以了,當這些多媒體數據在客戶機上播放時,文件的剩余部分 將繼續(xù)從流媒體服務器下載。

流(Streaming)是近年在Internet上出現的新概念,其定義非常廣泛,主要是指通過網絡傳輸 多媒體數據的技術總稱。流媒體包含廣義和狹義兩種內涵:廣義上的流媒體指的是使音頻和視頻形成穩(wěn)定和連續(xù)的傳輸流和回放流的一系列技術、方法和協(xié)議的總 稱,即流媒體技術;狹義上的流媒體是相對于傳統(tǒng)的下載-回放方式而言的,指的是一種從Internet上獲取音頻和視頻等多媒體數據的新方法,它能夠支持 多媒體數據流的實時傳輸和實時播放。通過運用流媒體技術,服務器能夠向客戶機發(fā)送穩(wěn)定和連續(xù)的多媒體數據流,客戶機在接收數據的同時以一個穩(wěn)定的速率回 放,而不用等數據全部下載完之后再進行回放。

由于受網絡帶寬、計算機處理能力和協(xié)議規(guī)范等方面的限制,要想從Internet上下載大 量的音頻和視頻數據,無論從下載時間和存儲空間上來講都是不太現實的,而流媒體技術的出現則很好地解決了這一難題。目前實現流媒體傳輸主要有兩種方法:順 序流(progressive streaming)傳輸和實時流(realtime streaming)傳輸,它們分別適合于不同的應用場合。

順序流傳輸

順 序流傳輸采用順序下載的方式進行傳輸,在下載的同時用戶可以在線回放多媒體數據,但給定時刻只能觀看已經下載的部分,不能跳到尚未下載的部分,也不能在傳 輸期間根據網絡狀況對下載速度進行調整。由于標準的HTTP服務器就可以發(fā)送這種形式的流媒體,而不需要其他特殊協(xié)議的支持,因此也常常被稱作 HTTP流式傳輸。順序流式傳輸比較適合于高質量的多媒體片段,如片頭、片尾或者廣告等。

實時流傳輸

實時流式傳輸保 證媒體信號帶寬能夠與當前網絡狀況相匹配,從而使得流媒體數據總是被實時地傳送,因此特別適合于現場事件。實時流傳輸支持隨機訪問,即用戶可以通過快進或 者后退操作來觀看前面或者后面的內容。從理論上講,實時流媒體一經播放就不會停頓,但事實上仍有可能發(fā)生周期性的暫?,F象,尤其是在網絡狀況惡化時更是如 此。與順序流傳輸不同的是,實時流傳輸需要用到特定的流媒體服務器,而且還需要特定網絡協(xié)議的支持。

二、流媒體協(xié)議

實時傳輸協(xié)議(Real-time Transport Protocol,RTP)是 在Internet上處理多媒體數據流的一種網絡協(xié)議,利用它能夠在一對一(unicast,單播)或者一對多(multicast,多播)的網絡環(huán)境中 實現傳流媒體數據的實時傳輸。RTP通常使用UDP來進行多媒體數據的傳輸,但如果需要的話可以使用TCP或者 ATM等其它協(xié)議,整個RTP協(xié)議由兩個密切相關的部分組成:RTP數據協(xié)議和RTCP控制協(xié)議。實時流協(xié)議(Real Time Streaming Protocol,RTSP)最早由Real Networks和Netscape公司共同提出,它位于RTP和RTCP之上,其目的是希望通過IP網絡有效地傳輸多媒體數據。

2.1 RTP數據協(xié)議

RTP數據協(xié)議負責對流媒體數據進行封包并實現媒體流的實時傳輸,每一個RTP數據報都由頭部(Header)負載(Payload)兩個部分組成,其中頭部前12個字節(jié)的含義是固定的,而負載則可以是音頻或者視頻數據。RTP數據報的頭部格式如圖1所示:

 

jrtplib介紹 - 黑黑的大鯊魚 - 黑黑的大鯊魚

 
圖1 RTP頭部格式

其中比較重要的幾個域及其意義如下:


     。CSRC記數(CC) 表示CSRC標識的數目。CSRC標識緊跟在RTP固定頭部之后,用來表示RTP數據報的來源,RTP協(xié)議允許在同一個會話中存在多個數據源,它們可以 通過RTP混合器合并為一個數據源。例如,可以產生一個CSRC列表來表示一個電話會議,該會議通過一個 RTP混合器將所有講話者的語音數據組合為一個RTP數據源。
    。負載類型(PT)  標明RTP負載的格式,包括所采用的編碼算法、采樣頻率、承載通道等。例如,類型2表明該RTP數據包中承載的是用ITU G.721算法編碼的語音數據,采樣頻率為8000Hz,并且采用單聲道。
    。序列號  用來為接收方提供探測數據丟失的方法,但如何處理丟失的數據則是應用程序自己的事情,RTP協(xié)議本身并不負責數據的重傳。
    。時間戳  記錄了負載中第一個字節(jié)的采樣時間,接收方能夠時間戳能夠確定數據的到達是否受到了延遲抖動的影響,但具體如何來補償延遲抖動則是應用程序自己的事情。
從RTP 數據報的格式不難看出,它包含了傳輸媒體的類型、格式、序列號、時間戳以及是否有附加數據等信息,這些都為實時的流媒體傳輸提供了相應的基礎。RTP 協(xié)議的目的是提供實時數據(如交互式的音頻和視頻)的端到端傳輸服務,因此在RTP中沒有連接的概念,它可以建立在底層的面向連接或面向非連接的傳輸協(xié)議 之上;RTP也不依賴于特別的網絡地址格式,而僅僅只需要底層傳輸協(xié)議支持組幀(Framing)和分段(Segmentation)就足夠了;另外 RTP 本身還不提供任何可靠性機制,這些都要由傳輸協(xié)議或者應用程序自己來保證。在典型的應用場合下,RTP一般是在傳輸協(xié)議之上作為應用程序的一部分加以實現的,如圖2所示:

jrtplib介紹 - 黑黑的大鯊魚 - 黑黑的大鯊魚

 
圖2 RTP與各種網絡協(xié)議的關系

2.2 RTCP控制協(xié)議

RTCP 控制協(xié)議需要與RTP數據協(xié)議一起配合使用,當應用程序啟動一個RTP會話時將同時占用兩個端口,分別供RTP和RTCP使用。RTP本身并不能為按序傳 輸數據包提供可靠的保證,也不提供流量控制和擁塞控制,這些都由RTCP來負責完成。通常RTCP會采用與RTP相同的分發(fā)機制,向會話中的所有成員周期 性地發(fā)送控制信息,應用程序通過接收這些數據,從中獲取會話參與者的相關資料,以及網絡狀況、分組丟失概率等反饋信息,從而能夠對服務質量進行控制或者對 網絡狀況進行診斷。

RTCP協(xié)議的功能是通過不同的RTCP數據報來實現的,主要有如下幾種類型:


。SR  發(fā)送端報告,所謂發(fā)送端是指發(fā)出RTP數據報的應用程序或者終端,發(fā)送端同時也可以是接收端。
。RR  接收端報告,所謂接收端是指僅接收但不發(fā)送RTP數據報的應用程序或者終端。
。SDES  源描述,主要功能是作為會話成員有關標識信息的載體,如用戶名、郵件地址、電話號碼等,此外還具有向會話成員傳達會話控制信息的功能。
BYE  通知離開,主要功能是指示某一個或者幾個源不再有效,即通知會話中的其他成員自己將退出會話。
。APP  由應用程序自己定義,解決了RTCP的擴展性問題,并且為協(xié)議的實現者提供了很大的靈活性。
RTCP數據報攜帶有服務質量監(jiān)控的必要信息,能夠對服務質量進行動態(tài)的調整,并能夠對網絡擁塞進行有效的控制。由于RTCP數據報采用的是多播方式,因此會話中的所有成員都可以通過RTCP數據報返回的控制信息,來了解其他參與者的當前情況。

在 一個典型的應用場合下,發(fā)送媒體流的應用程序將周期性地產生發(fā)送端報告SR,該RTCP數據報含有不同媒體流間的同步信息,以及已經發(fā)送的數據報和字節(jié)的 計數,接收端根據這些信息可以估計出實際的數據傳輸速率。另一方面,接收端會向所有已知的發(fā)送端發(fā)送接收端報告RR,該RTCP數據報含有已接收數據報的 最大序列號、丟失的數據報數目、延時抖動和時間戳等重要信息,發(fā)送端應用根據這些信息可以估計出往返時延,并且可以根據數據報丟失概率和時延抖動情況動態(tài) 調整發(fā)送速率,以改善網絡擁塞狀況,或者根據網絡狀況平滑地調整應用程序的服務質量。

2.3 RTSP實時流協(xié)議

作為一個應用層協(xié)議,RTSP提供了一個可供擴展的框架,它的意義在于使得實時流媒體數據的受控和點播變得可能。總的說來,RTSP是一個流媒體表示協(xié)議,主要用來控制具有實時特性的數據發(fā)送,但它本身并不傳輸數據,而是必須依賴于下層傳輸協(xié)議所提供的某些服務。RTSP可以對流媒體提供諸如播放、暫停、快進等操作,它負責定義具體的控制消息、操作方法、狀態(tài)碼等,此外還描述了與RTP間的交互操作。

RTSP 在制定時較多地參考了 HTTP/1.1協(xié)議,甚至許多描述與HTTP/1.1完全相同。RTSP之所以特意使用與HTTP/1.1類似的語法和操作,在很大程度上是為了兼容現 有的Web基礎結構,正因如此,HTTP/1.1的擴展機制大都可以直接引入到RTSP中。

由 RTSP控制的媒體流集合可以用表示描述(Presentation Description)來定義,所謂表示是指流媒體服務器提供給客戶機的一個或者多個媒體流的集合,而表示描述則包含了一個表示中各個媒體流的相關信 息,如數據編碼/解碼算法、網絡地址、媒體流的內容等。

雖然RTSP服務器同樣也使用標識符來區(qū)別每一流連接會話 (Session),但 RTSP連接并沒有被綁定到傳輸層連接(如TCP等),也就是說在整個RTSP連接期間,RTSP用戶可打開或者關閉多個對RTSP服務器的可靠傳輸連接 以發(fā)出RTSP 請求。此外,RTSP連接也可以基于面向無連接的傳輸協(xié)議(如UDP等)。

RTSP協(xié)議目前支持以下操作:


。檢索媒體  允許用戶通過HTTP或者其它方法向媒體服務器提交一個表示描述。如表示是組播的,則表示描述就包含用于該媒體流的組播地址和端口號;如果表示是單播的,為了安全在表示描述中應該只提供目的地址。
。邀請加入  媒體服務器可以被邀請參加正在進行的會議,或者在表示中回放媒體,或者在表示中錄制全部媒體或其子集,非常適合于分布式教學。
。添加媒體  通知用戶新加入的可利用媒體流,這對現場講座來講顯得尤其有用。與HTTP/1.1類似,RTSP請求也可以交由代理、通道或者緩存來進行處理。
三、流媒體編程

RTP 是目前解決流媒體實時傳輸問題的最好辦法,如果需要在Linux平臺上進行實時流媒體編程,可以考慮使用一些開放源代碼的RTP庫,如LIBRTP、 JRTPLIB等。 JRTPLIB是一個面向對象的RTP庫,它完全遵循RFC 1889設計,在很多場合下是一個非常不錯的選擇,下面就以JRTPLIB為例,講述如何在Linux平臺上運用RTP協(xié)議進行實時流媒體編程。

3.1 環(huán)境搭建

JRTPLIB 是一個用C++語言實現的RTP庫,目前已經可以運行在Windows、Linux、FreeBSD、Solaris、Unix和 VxWorks等多種操作系統(tǒng)上。要為Linux 系統(tǒng)安裝JRTPLIB,首先從JRTPLIB的網站(http: //lumumba./jori/jrtplib/jrtplib.html)下載最新的源碼包,此處使用的是jrtplib- 2.7b.tar.bz2。假設下載后的源碼包保存在/usr/local/src目錄下,執(zhí)行下面的命令可以對其進行解壓縮:


[root@linuxgam src]# bp2 -dc jrtplib-2.7b.tar.bz2 | tar xvf -


接下去需要對JRTPLIB進行配置和編譯:


[root@linuxgam src]# cd jrtplib-2.7

[root@linuxgam jrtplib-2.7b]# ./configure

[root@linuxgam jrtplib-2.7b]# make


最后再執(zhí)行如下命令就可以完成JRTPLIB的安裝:


[root@linuxgam jrtplib-2.7b]# make install


3.2 初始化

在 使用JRTPLIB進行實時流媒體數據傳輸之前,首先應該生成RTPSession類的一個實例來表示此次RTP會話,然后調用Create() 方法來對其進行初始化操作。RTPSession類的Create()方法只有一個參數,用來指明此次RTP會話所采用的端口號。清單1給出了一個最簡單 的初始化框架,它只是完成了RTP會話的初始化工作,還不具備任何實際的功能。

代碼清單1:initial.cpp


#i nclude "rtpsession.h"  

int main(void)

     RTPSession sess; sess.Create(5000); 

     return 0;

}


如 果RTP會話創(chuàng)建過程失敗,Create()方法將會返回一個負數,通過它雖然可以很容易地判斷出函數調用究竟是成功的還是失敗的,但卻很難明白出錯的原 因到底什么。JRTPLIB采用了統(tǒng)一的錯誤處理機制,它提供的所有函數如果返回負數就表明出現了某種形式的錯誤,而具體的出錯信息則可以通過調用 RTPGetErrorString()函數得到。RTPGetErrorString()函數將錯誤代碼作為參數傳入,然后返回該錯誤代碼所對應的錯誤 信息。清單2給出了一個更加完整的初始化框架,它可以對RTP會話初始化過程中所產生的錯誤進行更好的處理:

代碼清單2:framework.cpp


#i nclude

#i nclude "rtpsession.h"

int main(void)

RTPSession sess; 

int status; 

 char* msg; 

sess.Create(6000);  //此處是不是應該為status = sess.Create(6000);

msg = RTPGetErrorString(status); 

printf("Error String: %s\\n", msg); 

return 0;

}


設 置恰當的時戳單元,是RTP會話初始化過程所要進行的另外一項重要工作,這是通過調用RTPSession類的SetTimestampUnit ()方法來實現的,該方法同樣也只有一個參數,表示的是以秒為單元的時戳單元。例如,當使用RTP會話傳輸8000Hz采樣的音頻數據時,由于時戳每秒鐘 將遞增8000,所以時戳單元相應地應該被設置成1/8000:


sess.SetTimestampUnit(1.0/8000.0);


3.3 數據發(fā)送

當RTP 會話成功建立起來之后,接下去就可以開始進行流媒體數據的實時傳輸了。首先需要設置好數據發(fā)送的目標地址,RTP協(xié)議允許同一會話存在多個目標地址,這可 以通過調用RTPSession類的AddDestination()、DeleteDestination()和 ClearDestinations()方法來完成。例如,下面的語句表示的是讓RTP會話將數據發(fā)送到本地主機的6000端口:


unsigned long addr = ntohl(inet_addr("127.0.0.1"));

sess.AddDestination(addr, 6000);


目標地址全部指定之后,接著就可以調用RTPSession類的SendPacket()方法,向所有的目標地址發(fā)送流媒體數據。SendPacket()是RTPSession類提供的一個重載函數,它具有下列多種形式:


int SendPacket(void *data,int len)

int SendPacket(void *data,int len,unsigned char pt,bool mark,unsigned long timestampinc)

int SendPacket(void *data,int len,unsigned short hdrextID,void *hdrextdata,int numhdrextwords)

int SendPacket(void *data,int len,unsigned char pt,bool mark,unsigned long timestampinc,unsigned short hdrextID,

                         void *hdrextdata,int numhdrextwords)


SendPacket()最典型的用法是類似于下面的語句,其中第一個參數是要被發(fā)送的數據,而第二個參數則指明將要發(fā)送數據的長度,再往后依次是RTP負載類型、標識和時戳增量。


sess.SendPacket(buffer, 5, 0, false, 10);


對 于同一個RTP會話來講,負載類型、標識和時戳增量通常來講都是相同的,JRTPLIB允許將它們設置為會話的默認參數,這是通過調用 RTPSession類的SetDefaultPayloadType()、SetDefaultMark()和 SetDefaultTimeStampIncrement()方法來完成的。為RTP會話設置這些默認參數的好處是可以簡化數據的發(fā)送,例如,如果為 RTP會話設置了默認參數:


sess.SetDefaultPayloadType(0);

sess.SetDefaultMark(false);

sess.SetDefaultTimeStampIncrement(10);


之后在進行數據發(fā)送時只需指明要發(fā)送的數據及其長度就可以了:


sess.SendPacket(buffer, 5);


3.4 數據接收

對 于流媒體數據的接收端,首先需要調用RTPSession類的PollData()方法來接收發(fā)送過來的RTP或者RTCP數據報。由于同一個 RTP會話中允許有多個參與者(源),你既可以通過調用RTPSession類的GotoFirstSource()和GotoNextSource() 方法來遍歷所有的源,也可以通過調用RTPSession類的GotoFirstSourceWithData()和 GotoNextSourceWithData()方法來遍歷那些攜帶有數據的源。在從RTP會話中檢測出有效的數據源之后,接下去就可以調用 RTPSession類的GetNextPacket()方法從中抽取RTP數據報,當接收到的RTP數據報處理完之后,一定要記得及時釋放。下面的代碼 示范了該如何對接收到的RTP數據報進行處理:


if (sess.GotoFirstSourceWithData())

  do {   

         RTPPacket *pack;

         pack = sess.GetNextPacket();         // 處理接收到的數據   

         delete pack; 

      } while (sess.GotoNextSourceWithData());

}


JRTPLIB為RTP數據報定義了三種接收模式,其中每種接收模式都具體規(guī)定了哪些到達的RTP數據報將會被接受,而哪些到達的RTP數據報將會被拒絕。通過調用RTPSession類的SetReceiveMode()方法可以設置下列這些接收模式:

。RECEIVEMODE_ALL  缺省的接收模式,所有到達的RTP數據報都將被接受;
。RECEIVEMODE_IGNORESOME 除了某些特定的發(fā)送者之外,所有到達的RTP數據報都將被接受,而被拒絕的發(fā)送者列表可以通過調用AddToIgnoreList()、 DeleteFromIgnoreList()和ClearIgnoreList()方法來進行設置;
。RECEIVEMODE_ACCEPTSOME 除了某些特定的發(fā)送者之外,所有到達的RTP數據報都將被拒絕,而被接受的發(fā)送者列表可以通過調用AddToAcceptList ()、DeleteFromAcceptList和ClearAcceptList ()方法來進行設置。
3.5 控制信息

JRTPLIB 是一個高度封裝后的RTP庫,程序員在使用它時很多時候并不用關心RTCP數據報是如何被發(fā)送和接收的,因為這些都可以由 JRTPLIB自己來完成。只要PollData()或者SendPacket()方法被成功調用,JRTPLIB就能夠自動對到達的RTCP數據報進行 處理,并且還會在需要的時候發(fā)送RTCP數據報,從而能夠確保整個RTP會話過程的正確性。

而另一方面,通過調用RTPSession 類提供的SetLocalName()、SetLocalEMail()、 SetLocalLocation()、SetLocalPhone()、SetLocalTool()和SetLocalNote()方法, JRTPLIB又允許程序員對RTP會話的控制信息進行設置。所有這些方法在調用時都帶有兩個參數,其中第一個參數是一個char型的指針,指向將要被設 置的數據;而第二個參數則是一個int型的數值,表明該數據中的前面多少個字符將會被使用。例如下面的語句可以被用來設置控制信息中的電子郵件地址:


sess.SetLocalEMail("xiaowp@linuxgam.com",19);


在RTP 會話過程中,不是所有的控制信息都需要被發(fā)送,通過調用RTPSession類提供的EnableSendName()、 EnableSendEMail()、EnableSendLocation()、EnableSendPhone()、EnableSendTool ()和EnableSendNote()方法,可以為當前RTP會話選擇將被發(fā)送的控制信息。

3.6 實際應用

最后通過一個簡單的流媒體發(fā)送-接收實例,介紹如何利用JRTPLIB來進行實時流媒體的編程。清單3給出了數據發(fā)送端的完整代碼,它負責向用戶指定的IP地址和端口,不斷地發(fā)送RTP數據包:

代碼清單3:sender.cpp


#i nclude

#i nclude

#i nclude "rtpsession.h"

// 錯誤處理函數

void checkerror(int err)

      if (err < 0)

      {   

         char* errstr = RTPGetErrorString(err);   

         printf("Error:%s\\n", errstr);   

         exit(-1); 

      }

}

int main(int argc, char** argv)

     RTPSession sess; 

     unsigned long destip; 

     int destport; 

     int portbase = 6000; 

     int status, index; 

     char buffer[128]; 

     if (argc != 3)

     {   

         printf("Usage: ./sender destip destport\\n");   

         return -1; 

     } 

 // 獲得接收端的IP地址和端口號 

     destip = inet_addr(argv[1]); 

      if (destip == INADDR_NONE)

      {   

        printf("Bad IP address specified.\\n");   

         return -1; 

      } 

     destip = ntohl(destip); 

     destport = atoi(argv[2]); 

// 創(chuàng)建RTP會話 

     status = sess.Create(portbase); 

     checkerror(status); 

// 指定RTP數據接收端 

     status = sess.AddDestination(destip, destport); 

     checkerror(status); 

// 設置RTP會話默認參數 

      sess.SetDefaultPayloadType(0); 

      sess.SetDefaultMark(false); 

      sess.SetDefaultTimeStampIncrement(10); 

// 發(fā)送流媒體數據 

      index = 1; 

      do {   

           sprintf(buffer, "%d: RTP packet", index ++);   

           sess.SendPacket(buffer, strlen(buffer));   

           printf("Send packet !\\n"); 

      } while(1); 

      return 0;

}


清單4則給出了數據接收端的完整代碼,它負責從指定的端口不斷地讀取RTP數據包:

代碼清單4:receiver.cpp


#i nclude

#i nclude "rtpsession.h"

#i nclude "rtppacket.h"

// 錯誤處理函數

void checkerror(int err)

     if (err < 0)

     {   

         char* errstr = RTPGetErrorString(err);   

         printf("Error:%s\\n", errstr);

         exit(-1); 

    }

}

int main(int argc, char** argv)

{

  RTPSession sess;

  int localport;

  int status;

  if (argc != 2)

 {

    printf("Usage: ./sender localport\\n");

    return -1;

  }

   // 獲得用戶指定的端口號

  localport = atoi(argv[1]); 

 // 創(chuàng)建RTP會話

  status = sess.Create(localport);

  checkerror(status);

  do {

    // 接受RTP數據

    status = sess.PollData();

 // 檢索RTP數據源

    if (sess.GotoFirstSourceWithData())

     {     

     do { 

          RTPPacket* packet;

         // 獲取RTP數據報 

         while ((packet = sess.GetNextPacket()) != NULL)

         {

             printf("Got packet !\\n");

             // 刪除RTP數據報

             delete packet;

         }

      } while (sess.GotoNextSourceWithData());

    }

  } while(1);

  return 0;

}


本文源碼下載

四、小結

隨 著多媒體數據在 Internet上所承擔的作用變得越來越重要,需要實時傳輸音頻和視頻等多媒體數據的場合也將變得越來越多,如IP電話、視頻點播、在線會議等。RTP 是用來在Internet上進行實時流媒體傳輸的一種協(xié)議,目前已經被廣泛地應用在各種場合,JRTPLIB是一個面向對象的RTP封裝庫,利用它可以很 方便地完成Linux平臺上的實時流媒體編程。

五、參考資源

1. 在JRTPLIB的網站http://lumumba./jori/jrtplib/jrtplib.html上,可以下載到JRTPLIB最新的源碼包,并且還能找到一些與RTP相關的資源。

2. 顧淑珍等編著,寬帶增值服務開發(fā)實例,北京:機械工業(yè)出版社,2002

3. 黃永峰等編著,IP網絡多媒體通信技術,北京:人民郵電出版社,2003

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/ipromiseu/archive/2009/09/08/4531613.aspx

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    欧美一区日韩一区日韩一区| 夜夜嗨激情五月天精品| 亚洲天堂一区在线播放| 国产又黄又猛又粗又爽的片| 精品少妇一区二区三区四区| 亚洲国产性生活高潮免费视频| 丝袜视频日本成人午夜视频| 欧美日韩精品久久第一页| 九九蜜桃视频香蕉视频| 久热这里只有精品九九| 老司机精品视频免费入口| 亚洲清纯一区二区三区| 丰满少妇被猛烈撞击在线视频| 黄片在线免费看日韩欧美| 国产中文字幕一二三区| 日韩欧美高清国内精品| 国内午夜精品视频在线观看| 男人和女人干逼的视频| 亚洲欧美日韩精品永久| 大香蕉久久精品一区二区字幕| 亚洲欧美日韩国产成人| 偷拍偷窥女厕一区二区视频| 91人妻丝袜一区二区三区| 日韩性生活视频免费在线观看| 日韩欧美一区二区久久婷婷| 国产又色又爽又黄又大| 久久综合狠狠综合久久综合| 国产免费黄片一区二区| 久久国产成人精品国产成人亚洲| 亚洲国产欧美精品久久 | 午夜福利大片亚洲一区| 亚洲国产成人爱av在线播放下载| 日韩精品一区二区一牛| 国内欲色一区二区三区| 少妇肥臀一区二区三区| 国产午夜精品美女露脸视频| 欧美日韩校园春色激情偷拍| 四十女人口红哪个色好看| 日韩日韩日韩日韩在线| 在线观看视频日韩精品| 国产精品一区二区三区激情|