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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章