从上篇live555点播服务器流程简单分析我们对启动流媒体服务器可以有一个大致的概念,接下来我们深入分析一下,整个rtsp的交互过程。
从上篇我们可以有一个大概的知识点:
一个server, 这个server下包含几个成员信息
1)fServerMediaSessions:哈希表<会话名称,会话>,serverMediaSession流媒体会话信息;
2)fClientSessions:哈希表<sessionIdStr,clientSession>,客户端会话信息,RTSPClientSession是ClientSession的派生类,在收到客户端setup后创建,主要负责setup和play的响应处理;
3)fClientConnections:哈希表<ClientConnection,ClientConnection>,客户端连接信息,RTSPClientConnection是ClientConnection的派生类,主要负责对客户端发来数据的处理分析(调用incomingRequestHandler函数);并处理客户端发来的options和describe请求;当收到客户端发来的setup请求后需要创建RTSPClientSession来处理setup的具体处理;
在main函数中创建264会话时,会创建ServerMediaSession;在GenericMediaServer的构造函数中将监听套接字与监听处理函数(静态成员函数incomingConnectionHandler)进行关联,添加到Sock任务队列中,在后面的select时用来处理任务,找到相关回调函数;
当有客户端连接时会创建ClinetSession,incomingConnectionHandler()——>accept()——>createNewClientConnection——>将ClientConnection加入哈希表fClientConnections中,同时将客户端sock与其处理函数(静态成员函数incomingRequestHandler())进行关联,将其添加到sock任务队列fHandlers中,fHandlers是一个双向链表用于保存相关sock与其应该调用的处理函数;
当客户端发送options或dscribe请求时,在incomingRequestHandler()函数中进行接收处理readSocket()——>handleRequestBytes()——>parseRTSPRequestString()分析客户端发来的请求,如果该请求中没有包含会话ID则从哈希表根据rtsp后缀(即会话名称,注意此名称并不一定是真实的文件名称test.264只是另起的一个在加入哈希表时与该文件进行映射的名称而已),session = fOurServer.lookupServerMediaSession(urlTotalSuffix);最后调用找到的会话session对sdp信息进行封装,对rtsp回应进行封装。
当客户端发送setup时,大体同describe,如果未包含会话ID,则创建一个客户端会话
//gxq 创建客户端会话RTSPClientSession,并存入server中的哈希表fClientConnections中 clientSession= (RTSPServer::RTSPClientSession*)fOurRTSPServer.createNewClientSessionWithId();
然后使用此会话处理客户端的setup请求
1 clientSession->handleCmd_SETUP(this, urlPreSuffix, urlSuffix, (char const*)fRequestBuffer); 2 playAfterSetup = clientSession->fStreamAfterSETUP;
在此需要说明一下rtspserver是怎么一步一步与clientsession,clientconnection进行关联的。
首先在GenericMediaServer构造函数中使用env.taskScheduler().turnOnBackgroundReadHandling(fServerSocket, incomingConnectionHandler, this);将监听socket与监听处理函数进行关联将其加入sock任务队列fHandlers,
队列的节点HandlerDescriptor包含如下信息:
1)socketNum,网络套接字;
2)conditionSet,sock可读、可写还是发生异常的状态集合;
3)handlerProc,该sock的任务处理函数;
4)clientData,这个就是上面传入的this指针也即GenericMediaServer指针;
当监听到有客户端连接调用监听任务处理函数incomingConnectionHandler:
(*handler->handlerProc)(handler->clientData, resultConditionSet);
上面的clientData就是刚刚讲到的server指针,在GenericMediaServer的成员函数incomingConnectionHandler中创建客户端sock和clientconnections(通过子类RTSPServer重写的createNewClientConnection()函数创建),至此fServer与clientconnection有了直接联系,并且将fServer的指针赋值给了RTSPClientConnection成员变量fOurRTSPServer,clientconnection加入到了fServer的成员变量fClientConnections中;同时在ClientConnection构造函数中对该客户端sock进行任务处理函数绑定
envir().taskScheduler().setBackgroundHandling(fOurSocket, SOCKET_READABLE|SOCKET_EXCEPTION, incomingRequestHandler, this);
这里的fOurSocket是客户端sock,incomingRequestHandler(ClientConnection的静态成员函数)是select时发现该sock可读的任务处理函数,this就是ClientConnection指针,至此sock和ClientConnection指针对象被关联到一起放入到了sock任务队列中;
在ClientConnection::incomingRequestHandler中处理客户端发来的setup请求时使用RTSPClientConnection成员变量fOurRTSPServer创建客户端会话RTSPClientSession(并且将fServer的指针赋值给了RTSPClientSession成员变量fOurRTSPServer),将加入到fServer的成员变量fClientSessions中; 至此服务、客户端连接、客户端会话的信息就可以串起来了。
转载于:https://www.cnblogs.com/guoliushui/p/8650085.html