【创建】
服务端与客户端建立一个连接,就会生成一个ClientConnection。
ClientConnection在处理SETUP Command时,会生成与自身对应的ClientSession(createNewClientSessionWithId)。
void RTSPServer::RTSPClientConnection::handleRequestBytes(int newBytesRead) {
int numBytesRemaining = 0;
++fRecursionCount;
do {
RTSPServer::RTSPClientSession* clientSession = NULL;
...
} else if (strcmp(cmdName, "SETUP") == 0) {
Boolean areAuthenticated = True;
if (!requestIncludedSessionId) {
// No session id was present in the request.
// So create a new "RTSPClientSession" object for this request.
// But first, make sure that we're authenticated to perform this command:
char urlTotalSuffix[2*RTSP_PARAM_STRING_MAX];
// enough space for urlPreSuffix/urlSuffix'\0'
urlTotalSuffix[0] = '\0';
if (urlPreSuffix[0] != '\0') {
strcat(urlTotalSuffix, urlPreSuffix);
strcat(urlTotalSuffix, "/");
}
strcat(urlTotalSuffix, urlSuffix);
if (authenticationOK("SETUP", urlTotalSuffix, (char const*)fRequestBuffer)) {
clientSession
= (RTSPServer::RTSPClientSession*)fOurRTSPServer.createNewClientSessionWithId();
} else {
areAuthenticated = False;
}
}
if (clientSession != NULL) {
clientSession->handleCmd_SETUP(this, urlPreSuffix, urlSuffix, (char const*)fRequestBuffer);
playAfterSetup = clientSession->fStreamAfterSETUP;
在ClientSession::handleCmd_SETUP中将ClientConnectioin与ClientSession通过noteTcpStreamingOnSocket进行了关联。
void RTSPServer::RTSPClientSession
::handleCmd_SETUP(RTSPServer::RTSPClientConnection* ourClientConnection,
char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr) {
...
// Then, get server parameters from the 'subsession':
if (streamingMode == RTP_TCP) {
// Note that we'll be streaming over the RTSP TCP connection:
fStreamStates[trackNum].tcpSocketNum = ourClientConnection->fClientOutputSocket;
fOurRTSPServer.noteTCPStreamingOnSocket(fStreamStates[trackNum].tcpSocketNum, this, trackNum);
}
建立关系通过stremingOverTcpRecord的结构
void RTSPServer
::noteTCPStreamingOnSocket(int socketNum, RTSPClientSession* clientSession, unsigned trackNum) {
streamingOverTCPRecord* sotcpCur
= (streamingOverTCPRecord*)fTCPStreamingDatabase->Lookup((char const*)socketNum);
streamingOverTCPRecord* sotcpNew
= new streamingOverTCPRecord(clientSession->fOurSessionId, trackNum, sotcpCur);
fTCPStreamingDatabase->Add((char const*)socketNum, sotcpNew);
}
【析构】
1、从RTSPClientConnection析构看起,断开连接就应该将Connection进行删除
RTSPServer::RTSPClientConnection::~RTSPClientConnection() {
if (fOurSessionCookie != NULL) {
// We were being used for RTSP-over-HTTP tunneling. Also remove ourselves from the 'session cookie' hash table before we go:
fOurRTSPServer.fClientConnectionsForHTTPTunneling->Remove(fOurSessionCookie);
delete[] fOurSessionCookie;
}
closeSocketsRTSP();
}
2、接下来看closeSocketsRTSP
void RTSPServer::RTSPClientConnection::closeSocketsRTSP() {
// First, tell our server to stop any streaming that it might be doing over our output socket:
fOurRTSPServer.stopTCPStreamingOnSocket(fClientOutputSocket);
// Turn off background handling on our input socket (and output socket, if different); then close it (or them):
if (fClientOutputSocket != fClientInputSocket) {
envir().taskScheduler().disableBackgroundHandling(fClientOutputSocket);
::closeSocket(fClientOutputSocket);
}
fClientOutputSocket = -1;
closeSockets(); // closes fClientInputSocket
}
3、看stopTCPStreamingOnSocket
void RTSPServer::stopTCPStreamingOnSocket(int socketNum) {
// Close any stream that is streaming over "socketNum" (using RTP/RTCP-over-TCP streaming):
streamingOverTCPRecord* sotcp
= (streamingOverTCPRecord*)fTCPStreamingDatabase->Lookup((char const*)socketNum);
if (sotcp != NULL) {
do {
RTSPClientSession* clientSession
= (RTSPServer::RTSPClientSession*)lookupClientSession(sotcp->fSessionId);
if (clientSession != NULL) {
clientSession->deleteStreamByTrack(sotcp->fTrackNum);
}
streamingOverTCPRecord* sotcpNext = sotcp->fNext;
sotcp->fNext = NULL;
delete sotcp;
sotcp = sotcpNext;
} while (sotcp != NULL);
fTCPStreamingDatabase->Remove((char const*)socketNum);
}
}
4、看deleteStreamByTrack
void RTSPServer::RTSPClientSession::deleteStreamByTrack(unsigned trackNum) {
if (trackNum >= fNumStreamStates) return; // sanity check; shouldn't happen
if (fStreamStates[trackNum].subsession != NULL) {
fStreamStates[trackNum].subsession->deleteStream(fOurSessionId, fStreamStates[trackNum].streamToken);
fStreamStates[trackNum].subsession = NULL;
}
// Optimization: If all subsessions have now been deleted, then we can delete ourself now:
Boolean noSubsessionsRemain = True;
for (unsigned i = 0; i < fNumStreamStates; ++i) {
if (fStreamStates[i].subsession != NULL) {
noSubsessionsRemain = False;
break;
}
}
if (noSubsessionsRemain) delete this;
}
最后一行的delete this将ClientSession进行了析构