Exemplo n.º 1
0
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;
}
Exemplo n.º 2
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;
}