NuPlayer處理RTSP請求消息

1.send函數

  int send( SOCKET s, const char FAR *buf, int len, int flags );
  不論是客戶端還是服務器端應用程序都用send函數來向TCP連接的另一端發送數據。
  客戶端程序一般用send函數向服務器發送請求,而服務器則通常用send函數來向客戶程序發送應答。
  參數列表:
    1.參數s指定發送端套接字描述符;
    2.參數buf指明一個存放應用程序要發送數據的緩衝區;
    3.參數 len指明實際要發送的數據的字節數;
    4.參數 flags一般置0。

  這裏只描述同步Socket的send函數的執行流程:
  1.當調用該函數時,send先比較待發送數據的長度len和套接字s的發送緩衝的長度。
  2.如果len大於s的發送緩衝區的長度,該函數返回SOCKET_ERROR;
  3.如果len小於或者等於s的發送緩衝區的長度,那麼send先檢查協議 是否正在發送s的發送緩衝中的數據。
  4.如果是就等待協議把數據發送完,如果協議還沒有開始發送s的發送緩衝中的數據或者s的發送緩衝中沒有數據,那麼 send就比較s的發送緩衝區的剩餘空間和len。
  5.如果len大於剩餘空間大小send就一直等待協議把s的發送緩衝中的數據發送完。
  6.如果len小於剩餘 空間大小send就僅僅把buf中的數據copy到剩餘空間裏(注意並不是send把s的發送緩衝中的數據傳到連接的另一端的,而是協議傳的,send僅僅是把buf中的數據copy到s的發送緩衝區的剩餘空間裏)。
  7.如果send函數copy數據成功,就返回實際copy的字節數,如果send在copy數據時出現錯誤,那麼send就返回SOCKET_ERROR;如果send在等待協議傳送數據時網絡斷開的話,那麼send函數也返回SOCKET_ERROR。

  注意:
  send函數把buf中的數據成功copy到s的發送緩衝的剩餘空間裏後它就返回了,但是此時這些數據並不一定馬上被傳到連接的另一端。如果協議在後續的傳送過程中出現網絡錯誤的話,那麼下一個Socket函數就會返回SOCKET_ERROR。(每一個除send外的Socket函數在執行的最開始總要先等待套接字的發送緩衝中的數據被協議傳送完畢才能繼續,如果在等待時出現網絡錯誤,那麼該Socket函數就返回 SOCKET_ERROR)

  注意:
  在Unix系統下,如果send在等待協議傳送數據時網絡斷開的話,調用send的進程會接收到一個SIGPIPE信號,進程對該信號的默認處理是進程終止。
  
  Send函數的返回值有三類:
  (1)返回值=0:
  (2)返回值<0:發送失敗,錯誤原因存於全局變量errno中
  (3)返回值>0:表示發送的字節數(實際上是拷貝到發送緩衝中的字節數)
  
  錯誤代碼:
  EBADF 參數s 非合法的socket處理代碼。
  EFAULT 參數中有一指針指向無法存取的內存空間
  ENOTSOCK 參數s爲一文件描述詞,非socket。
  EINTR 被信號所中斷。
  EAGAIN 此操作會令進程阻斷,但參數s的socket爲不可阻斷。
  ENOBUFS 系統的緩衝內存不足
  ENOMEM 核心內存不足
  EINVAL 傳給系統調用的參數不正確。

2.安卓N版本NuPlayer處理RTSP請求消息的流程

bool ARTSPConnection::handleServerRequest(const sp<ARTSPResponse> &request) {
    // Implementation of server->client requests is optional for all methods
    // but we do need to respond, even if it's just to say that we don't
    // support the method.

    //上面三行英文註釋的意思就是安卓N版本的nuplayer播放框架對rtsp流的服務端的請求消息沒有實現相應的處理
    //即部支持服務端的請求消息,接下來需要向服務端發送迴應消息告訴服務端
    ssize_t space1 = request->mStatusLine.find(" ");
    CHECK_GE(space1, 0);

    //構造rtsp迴應消息的消息狀態行:"RTSP/1.0 501 Not Implemented\r\n"
    AString response;
    response.append("RTSP/1.0 501 Not Implemented\r\n");

    //從服務端發送過來的請求消息中的header lines中獲取key爲cseq的header line
    //這裏需要注意的是cseq表示一對兒rtsp請求-應答這一對兒消息
    ssize_t i = request->mHeaders.indexOfKey("cseq");

    if (i >= 0) {
        //得到key爲cseq的字符表示
        AString value = request->mHeaders.valueAt(i);

        //將字符表示的cseq的值轉還成整數表示
        unsigned long cseq;
        if (!ParseSingleUnsignedLong(value.c_str(), &cseq)) {
            return false;
        }

        //構造key爲cseq的header line並緊跟着添加在需要發送給服務端的應答消息response的狀態行後面
        response.append("CSeq: ");
        response.append(cseq);
        response.append("\r\n");
    }

    //在消息的結尾加上"\r\n"表示消息頭部的結束
    response.append("\r\n");

    size_t numBytesSent = 0;
    while (numBytesSent < response.size()) {
        //調用send函數將該消息response發送給服務端
        ssize_t n =
            send(mSocket, response.c_str() + numBytesSent,
                 response.size() - numBytesSent, 0);

        if (n < 0 && errno == EINTR) {
            //當send函數的錯誤碼errno爲EINTR說明信號只是被沖斷
            //跳過當前循環,繼續發送
            continue;
        }

        if (n <= 0) {
            if (n == 0) {
                // Server closed the connection.
                ALOGE("Server unexpectedly closed the connection.");
            } else {
                ALOGE("Error sending rtsp response (%s).", strerror(errno));
            }

            performDisconnect();

            return false;
        }

        numBytesSent += (size_t)n;
    }

    return true;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章