📄 tcpexactive.cpp
字号:
#include <e32std.h>
#include <es_sock.h>
#include <in_sock.h>
#include <Uri16.h>
#include "TCPExActive.h"
namespace // anon
{
#if defined(_DEBUG)
_LIT (KDebugMsgResolved,"Resolved") ;
_LIT (KDebugMsgResolveFailed,"Not Resolved") ;
_LIT (KDebugMsgOpenFailed,"Can't Open") ;
_LIT (KDebugMsgConnecting, "Connecting") ;
_LIT (KDebugMsgConnectFailed, "Can't Connect") ;
_LIT (KDebugMsgSending, "Sending") ;
_LIT (KDebugMsgSendFailed, "Send Failed");
_LIT (KDebugMsgReceiving, "Receiving") ;
_LIT (KDebugMsgReceivedChunk, "Received a chunk") ;
_LIT (KDebugMsgReceiveFailed, "Receive Failed") ;
#endif // ifdef _DEBUG
} // anon namespace
//
// The usual Symbian OS two-phase construction stuff
//
CRetrieveHttp* CRetrieveHttp::NewL(MRetrieveHttpCallbacks& aCallback)
{
CRetrieveHttp* self=NewLC(aCallback);
CleanupStack::Pop(self);
return self;
}
CRetrieveHttp* CRetrieveHttp::NewLC(MRetrieveHttpCallbacks& aCallback)
{
CRetrieveHttp* self = new(ELeave) CRetrieveHttp(aCallback);
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
void CRetrieveHttp::ConstructL() // second-phase constructor
{
iState = EIdle ;
// Add self to active scheduler
CActiveScheduler::Add(this) ;
// Connect to socket server
User::LeaveIfError (iSockServer.Connect()) ;
}
//
// Standard C++ constructor and destructor
//
CRetrieveHttp::CRetrieveHttp(MRetrieveHttpCallbacks& aCallback) : CActive(0), iCallbacks (aCallback) // first-phase C++ constructor
{
iState = EIdle ;
}
CRetrieveHttp::~CRetrieveHttp()
{
iSockServer.Close() ;
}
//
// Request function - Does a bit of validation on the URL, parses out server name
// Any extra url info is ignored, port is assumed to be 80 and resource is assumed to
// be /
//
void CRetrieveHttp::RequestL(const TDesC& aURL)
{
TUriParser url;
url.Parse(aURL);
if (url.Extract(EUriScheme).Compare(_L("http")) != 0)
{
// Invalid URL - didn't start with "HTTP://"
User::Leave(KErrArgument) ;
}
// Clear response strings
iResponse.Zero() ;
iResponseChunk.Zero() ;
iServerName.Copy(url.Extract(EUriHost));
// Construct HTTP: GET command
iRequest.Copy(_L8("GET / HTTP/1.0\r\n\r\n"));
#ifdef _DEBUG
User::InfoPrint (iServerName) ;
#endif
// Open resolver socket
User::LeaveIfError (iResolver.Open(iSockServer, KAfInet, KProtocolInetTcp)) ;
// Attempt to resolve name
iResolver.GetByName(iServerName, iHostAddress, iStatus) ;
// Move to next state
iState = EResolving ;
// Enable the active object
SetActive() ;
}
//
// Mandatory RunL from CActive - This is where it all happens, basically a big switch
// statement that implements a state machine that goes through all the stages of
// performing the "GET" operation
//
void CRetrieveHttp::RunL()
{
TBool finished = EFalse ;
switch (iState)
{
case EIdle:
// Shouldn't happen
break ;
case EResolving:
// Name resolution completed - check result, if OK open socket
// and advance state to EOpening
if (iStatus == KErrNone)
{
#ifdef _DEBUG
User::InfoPrint (KDebugMsgResolved) ;
#endif
// Recover server's IP address
TInetAddr address ;
address = iHostAddress().iAddr;
address.SetPort (80) ; // Assume always port 80 for now!
// Attempt to open the socket
if (iSocket.Open(iSockServer, KAfInet, KSockStream, KProtocolInetTcp))
{
#ifdef _DEBUG
User::InfoPrint (KDebugMsgOpenFailed) ;
#endif
iState =EFailed ;
finished = ETrue ;
}
else
{
#ifdef _DEBUG
User::InfoPrint (KDebugMsgConnecting) ;
#endif
iState = EConnecting ;
iSocket.Connect(address, iStatus) ;
}
}
else
{
#ifdef _DEBUG
User::InfoPrint (KDebugMsgResolveFailed) ;
#endif
iState = EFailed ;
finished = ETrue ;
}
break ;
case EConnecting:
// Socket sucessfully opened. Send preconstructed request to server,
// and advance state to ESending
if (iStatus == KErrNone)
{
#ifdef _DEBUG
User::InfoPrint(KDebugMsgSending) ;
#endif
iSocket.Write(iRequest, iStatus) ;
iState = ESending ;
}
else
{
#ifdef _DEBUG
User::InfoPrint(KDebugMsgConnectFailed) ;
#endif
iState = EFailed ;
finished = ETrue ;
}
break ;
case ESending:
// Request sent, Start receive process for first "chunk" of
// data and advance state to EReceiving
if (iStatus == KErrNone)
{
#ifdef _DEBUG
User::InfoPrint (KDebugMsgReceiving) ;
#endif
//iResponseLength = 0 ;
iSocket.RecvOneOrMore(iResponseChunk, 0, iStatus, iResponseChunkSizePkg) ;
iState = EReceiving ;
}
else
{
#ifdef _DEBUG
User::InfoPrint (KDebugMsgSendFailed) ;
#endif
iState = EFailed ;
finished = ETrue ;
}
break ;
case EReceiving:
// If we sucessfully got a chunk then ask for more, if we've
// finished then go to complete
if (iStatus == KErrNone)
{
#ifdef _DEBUG
User::InfoPrint (KDebugMsgReceivedChunk) ;
#endif
// Copy 8 bit characters into 16 bit response buffer
for(TInt copyPtr = 0; (copyPtr < iResponseChunk.Length()) && (iResponse.Length() < iResponse.MaxLength()); copyPtr++)
{
TChar ch = iResponseChunk[copyPtr];
if (ch != '\r') // HTTP uses \r\n line termination, which looks funny in a CEikLabel
iResponse.Append (iResponseChunk[copyPtr]) ;
}
if (iResponse.Length() == iResponse.MaxLength())
{
// Response buffer full - We'll call that a sucess and pass back what we got anyway!
iState = EComplete ;
finished = ETrue ;
}
else
{
// Issue another read request
iResponseChunk.Zero() ;
iSocket.RecvOneOrMore(iResponseChunk, 0, iStatus, iResponseChunkSizePkg) ;
}
}
else if (iStatus == KErrEof)
{
// Server has no more data to send - We've finished!
iState = EComplete ;
finished = ETrue ;
}
else
{
#ifdef _DEBUG
User::InfoPrint (KDebugMsgReceiveFailed) ;
#endif
iState = EFailed ;
finished = ETrue ;
}
break ;
// Either retrieve completed or oops! Close all sockets and
// free resources either way.
case EComplete:
case EFailed:
finished = ETrue ;
break ;
}
// Notify our "owner" of state change
iCallbacks.StateChange(iState) ;
if (finished)
DoCancel() ;
else
SetActive() ;
}
//
// Mandatory DoCancel - from CActive
//
void CRetrieveHttp::DoCancel()
{
// Close everything that might be open and cancel any outstanding
// operations.
iResolver.Close() ;
iSocket.CancelAll() ;
iSocket.Close() ;
}
//
// Very boring access method to get at the retrieved data.
//
TDesC &CRetrieveHttp::GetResponseData()
{
return iResponse ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -