SInt64 EasyCMSSession::Run() { OS_Error theErr = OS_NoErr; EventFlags events = this->GetEvents(); if(events & Task::kKillEvent) { qtss_printf("kill event but not handle it!\n"); } while(1) { switch (fState) { case kIdle://空闲 { qtss_printf("kIdle state \n"); if(!IsConnected()) { // TCPSocket未连接的情况,首先进行登录连接 Login(); } else { // TCPSocket已连接的情况下区分具体事件类型 if(events & Task::kStartEvent) { // CMSSession掉线,重新进行上线动作 if(kSessionOffline == fSessionStatus) Login(); } if(events & Task::kReadEvent) { // 对已连接的TCP进行消息读取 fState = kReadingRequest; } if(events & Task::kTimeoutEvent) { // 保活时间到,需要发送保活报文 Login(); } } // 如果有消息需要发送则进入发送流程 if (fOutputStream.GetBytesWritten() > 0) { fState = kSendingResponse; } if(kIdle == fState) return 0; break; } case kReadingRequest: { qtss_printf("kReadingRequest state \n"); // 读取锁,已经在处理一个报文包时,不进行新网络报文的读取和处理 OSMutexLocker readMutexLocker(&fReadMutex); // 网络请求报文存储在fInputStream中 if ((theErr = fInputStream.ReadRequest()) == QTSS_NoErr) { //如果RequestStream返回QTSS_NoErr,就表示已经读取了目前所到达的网络数据 //但,还不能构成一个整体报文,还要继续等待读取... fSocket->GetSocket()->SetTask(this); fSocket->GetSocket()->RequestEvent(EV_RE); return 0; } if ((theErr != QTSS_RequestArrived) && (theErr != E2BIG) && (theErr != QTSS_BadArgument)) { //Any other error implies that the input connection has gone away. // We should only kill the whole session if we aren't doing HTTP. // (If we are doing HTTP, the POST connection can go away) Assert(theErr > 0); // If we've gotten here, this must be an HTTP session with // a dead input connection. If that's the case, we should // clean up immediately so as to not have an open socket // needlessly lingering around, taking up space. Assert(!fSocket->GetSocket()->IsConnected()); this->ResetClientSocket(); return 0; } fState = kProcessingRequest; break; } case kProcessingRequest: { qtss_printf("kProcessingRequest state \n"); // 处理网络报文 Assert( fInputStream.GetRequestBuffer() ); Assert(fRequest == NULL); // 根据具体请求报文构造HTTPRequest请求类 fRequest = NEW HTTPRequest(&sServiceStr, fInputStream.GetRequestBuffer()); // 在这里,我们已经读取了一个完整的Request,并准备进行请求的处理,直到响应报文发出 // 在此过程中,此Session的Socket不进行任何网络数据的读/写; fReadMutex.Lock(); fSessionMutex.Lock(); // 清空发送缓冲区 fOutputStream.ResetBytesWritten(); // 网络请求超过了缓冲区,返回Bad Request if (theErr == E2BIG) { // 返回HTTP报文,错误码408 //(void)QTSSModuleUtils::SendErrorResponse(fRequest, qtssClientBadRequest, qtssMsgRequestTooLong); fState = kSendingResponse; break; } // Check for a corrupt base64 error, return an error if (theErr == QTSS_BadArgument) { //返回HTTP报文,错误码408 //(void)QTSSModuleUtils::SendErrorResponse(fRequest, qtssClientBadRequest, qtssMsgBadBase64); fState = kSendingResponse; break; } Assert(theErr == QTSS_RequestArrived); ProcessRequest(); // 每一步都检测响应报文是否已完成,完成则直接进行回复响应 if (fOutputStream.GetBytesWritten() > 0) { fState = kSendingResponse; } else { fState = kCleaningUp; } break; } case kSendingResponse: { qtss_printf("kSendingResponse state \n"); // 响应报文发送,确保完全发送 // Assert(fRequest != NULL); //发送响应报文 theErr = fOutputStream.Flush(); if (theErr == EAGAIN || theErr == EINPROGRESS) { // If we get this error, we are currently flow-controlled and should // wait for the socket to become writeable again // 如果收到Socket EAGAIN错误,那么我们需要等Socket再次可写的时候再调用发送 fSocket->GetSocket()->SetTask(this); fSocket->GetSocket()->RequestEvent(fSocket->GetEventMask()); this->ForceSameThread(); // We are holding mutexes, so we need to force // the same thread to be used for next Run() return 0; } else if (theErr != QTSS_NoErr) { // Any other error means that the client has disconnected, right? Assert(!this->IsConnected()); ResetClientSocket(); return 0; } fState = kCleaningUp; break; } case kCleaningUp: { qtss_printf("kCleaningUp state \n"); // 清理已经处理的请求或者已经发送的报文缓存 // Cleaning up consists of making sure we've read all the incoming Request Body // data off of the socket ////if (this->GetRemainingReqBodyLen() > 0) ////{ //// err = this->DumpRequestData(); //// if (err == EAGAIN) //// { //// fInputSocketP->RequestEvent(EV_RE); //// this->ForceSameThread(); // We are holding mutexes, so we need to force //// // the same thread to be used for next Run() //// return 0; //// } ////} // 一次请求的读取、处理、响应过程完整,等待下一次网络报文! this->CleanupRequest(); fState = kIdle; if(IsConnected()) { fSocket->GetSocket()->SetTask(this); fSocket->GetSocket()->RequestEvent(fSocket->GetEventMask()); } return 0; } } } return 0; }
/*! \brief 事件由ServiceSession Task进行处理,大多数为网络报文处理事件 \param \return 处理完成返回0,断开Session返回-1 \ingroup \see */ SInt64 CServiceSession::Run() { //获取事件类型 EventFlags events = this->GetEvents(); QTSS_Error err = QTSS_NoErr; QTSSModule* theModule = NULL; UInt32 numModules = 0; // Some callbacks look for this struct in the thread object OSThreadDataSetter theSetter(&fModuleState, NULL); //超时事件或者Kill事件,进入释放流程:清理 & 返回-1 if (events & Task::kKillEvent) fLiveSession = false; if(events & Task::kTimeoutEvent) { //客户端Session超时,暂时不处理 char msgStr[512]; qtss_snprintf(msgStr, sizeof(msgStr), "session timeout,release session\n"); QTSServerInterface::LogError(qtssMessageVerbosity, msgStr); return -1; } //正常事件处理流程 while (this->IsLiveSession()) { //报文处理以状态机的形式,可以方便多次处理同一个消息 switch (fState) { case kReadingFirstRequest://首次对Socket进行读取 { if ((err = fInputStream.ReadRequest()) == QTSS_NoErr) { //如果RequestStream返回QTSS_NoErr,就表示已经读取了目前所到达的网络数据 //但,还不能构成一个整体报文,还要继续等待读取... fInputSocketP->RequestEvent(EV_RE); return 0; } if ((err != QTSS_RequestArrived) && (err != E2BIG)) { // Any other error implies that the client has gone away. At this point, // we can't have 2 sockets, so we don't need to do the "half closed" check // we do below Assert(err > 0); Assert(!this->IsLiveSession()); break; } if ((err == QTSS_RequestArrived) || (err == E2BIG)) fState = kHaveCompleteMessage; } continue; case kReadingRequest://读取请求报文 { //读取锁,已经在处理一个报文包时,不进行新网络报文的读取和处理 OSMutexLocker readMutexLocker(&fReadMutex); //网络请求报文存储在fInputStream中 if ((err = fInputStream.ReadRequest()) == QTSS_NoErr) { //如果RequestStream返回QTSS_NoErr,就表示已经读取了目前所到达的网络数据 //但,还不能构成一个整体报文,还要继续等待读取... fInputSocketP->RequestEvent(EV_RE); return 0; } if ((err != QTSS_RequestArrived) && (err != E2BIG) && (err != QTSS_BadArgument)) { //Any other error implies that the input connection has gone away. // We should only kill the whole session if we aren't doing HTTP. // (If we are doing HTTP, the POST connection can go away) Assert(err > 0); if (fOutputSocketP->IsConnected()) { // If we've gotten here, this must be an HTTP session with // a dead input connection. If that's the case, we should // clean up immediately so as to not have an open socket // needlessly lingering around, taking up space. Assert(fOutputSocketP != fInputSocketP); Assert(!fInputSocketP->IsConnected()); fInputSocketP->Cleanup(); return 0; } else { Assert(!this->IsLiveSession()); break; } } fState = kHaveCompleteMessage; } case kHaveCompleteMessage://读取到完整的请求报文 { Assert( fInputStream.GetRequestBuffer() ); Assert(fRequest == NULL); //根据具体请求报文构造HTTPRequest请求类 fRequest = NEW HTTPRequest(&sServiceStr, fInputStream.GetRequestBuffer()); //在这里,我们已经读取了一个完整的Request,并准备进行请求的处理,直到响应报文发出 //在此过程中,此Session的Socket不进行任何网络数据的读/写; fReadMutex.Lock(); fSessionMutex.Lock(); //清空发送缓冲区 fOutputStream.ResetBytesWritten(); //网络请求超过了缓冲区,返回Bad Request if (err == E2BIG) { //返回HTTP报文,错误码408 //(void)QTSSModuleUtils::SendErrorResponse(fRequest, qtssClientBadRequest, qtssMsgRequestTooLong); fState = kSendingResponse; break; } // Check for a corrupt base64 error, return an error if (err == QTSS_BadArgument) { //返回HTTP报文,错误码408 //(void)QTSSModuleUtils::SendErrorResponse(fRequest, qtssClientBadRequest, qtssMsgBadBase64); fState = kSendingResponse; break; } Assert(err == QTSS_RequestArrived); fState = kFilteringRequest; } case kFilteringRequest: { //刷新Session保活时间 fTimeoutTask.RefreshTimeout(); //对请求报文进行解析 QTSS_Error theErr = SetupRequest(); //当SetupRequest步骤未读取到完整的网络报文,需要进行等待 if(theErr == QTSS_WouldBlock) { this->ForceSameThread(); fInputSocketP->RequestEvent(EV_RE); // We are holding mutexes, so we need to force // the same thread to be used for next Run() return 0;//返回0表示有事件才进行通知,返回>0表示规定事件后调用Run } //每一步都检测响应报文是否已完成,完成则直接进行回复响应 if (/*fRequest->HasResponseBeenSent()*/fOutputStream.GetBytesWritten() > 0) { fState = kSendingResponse; break; } fState = kPreprocessingRequest; break; } case kPreprocessingRequest: { //请求预处理过程 //TODO:报文处理过程 fState = kCleaningUp; break; } case kProcessingRequest: { if (fOutputStream.GetBytesWritten() == 0) { //如果到这里,响应报文还没有形成,返回500 Server Internal Error ////QTSSModuleUtils::SendErrorResponse(fRequest, qtssServerInternal, qtssMsgNoModuleForRequest); } fState = kSendingResponse; } case kSendingResponse: { //响应报文发送,确保完全发送 Assert(fRequest != NULL); //发送响应报文 err = fOutputStream.Flush(); if (err == EAGAIN) { // If we get this error, we are currently flow-controlled and should // wait for the socket to become writeable again //如果收到Socket EAGAIN错误,那么我们需要等Socket再次可写的时候再调用发送 fSocket.RequestEvent(EV_WR); this->ForceSameThread(); // We are holding mutexes, so we need to force // the same thread to be used for next Run() return 0; } else if (err != QTSS_NoErr) { // Any other error means that the client has disconnected, right? Assert(!this->IsLiveSession()); break; } fState = kCleaningUp; } case kCleaningUp: { // Cleaning up consists of making sure we've read all the incoming Request Body // data off of the socket if (this->GetRemainingReqBodyLen() > 0) { err = this->DumpRequestData(); if (err == EAGAIN) { fInputSocketP->RequestEvent(EV_RE); this->ForceSameThread(); // We are holding mutexes, so we need to force // the same thread to be used for next Run() return 0; } } //一次请求的读取、处理、响应过程完整,等待下一次网络报文! this->CleanupRequest(); fState = kReadingRequest; } } } //清空Session占用的所有资源 this->CleanupRequest(); //Session引用数为0,返回-1后,系统会将此Session删除 if (fObjectHolders == 0) return -1; //如果流程走到这里,Session实际已经无效了,应该被删除,但没有,因为还有其他地方引用了Session对象 return 0; }