I believe that my application requires a second thread (please correct me if I'm wrong): The application is supposed to do multiple http-connections using the HTTP support classes of Series 60 SDK 2.1 and wait for the result of each HTTP request before issuing the next request. As far as I have understood CActive, CActive cannot be used here. The problem I'm thinking about is the loop of connections that will be made - as I understood CActive will not preempt the requesting phone, it will only say "hi there, I'm waiting for something" and just go on. If I'm wrong, please tell me how this can be solved with CActive - otherwise, can someone tell me how to use threads in Symbian?
The problem I'm thinking about is the loop of connections that will be made
What do you mean?
Anyway, you don't have to use another thread just for this purpose. If you're concerned about multiple connections and/or multiple HTTP sessions, then a new thread will not solve your problem. The only thing you need to issue multiple HTTP requests is to use multiple RHTTPSession objects and that's all. Note that I can't see when active objects come into play here, because you can use these HTTP session without active objects: it uses callbacks, that is, you don't have to maintain request statuses, because you functions will simply called back.
and wait for the result of each HTTP request before issuing the next request.
I have a series of requests (I meant requests, not connections - sorry for that) that has to be done one after another, and the next cannot start until the previous has completed.
class CBlah : public CActive { enum TState { EState1, EState2 }
TState iState; };
void CBLah::RunL() { switch(iState) { case EState1: { iState = EState2; // do what ever to request state 2 break; } case EState2: { break; } } }
It's a very common pattern in Symbian OS programming, you should be able to find some better/more complete examples knocking about on NewLC I would think.
Hi... I have a related question: somebody said here that we should not use CActive with HTTP CLiente API because of it uses CallBack.... so should I use the HTTP Client API as a synchronous request and that´s all?
So what if it uses callbacks? You can still use CActive.
As a general rule avoid synchronous communications programming... What happens if your using the HTTP client in a synchronous way and the user presses Exit etc?? You app locks up until the current request has finished - its very ugly - and CActive solves it quite well without having to mess around with threads (in most cases anyway).
I agree with you... ..... I am newbie in using AO....
Could you justa ask one more question??
I have a CActive class that makes a bluetooth connection to read an information and then sends it to a servlet via HTTP. When I finish tha reading from BT, I make SetActive and then in RunL I make the HTTP connection... is it OK??? The programm gets locked after reading from BT and never makes tha HTTP connection..... I´m sure its a problem whith ActiveScheduler... do you have any idea of where can be the error? Maybe tha BT reading always pending???
I make SetActive and then in RunL I make the HTTP connection... is it OK???
Yes - providing you keep some kind of state so you know when your RunL gets called wheather its because of your bluetooth connection, or your HTTP connection.
i´ve been trying, but.... I really don´t know how to sove the problem... i´m gonna post my code... if someone has patience to read it., please do, I´ll be forever thankful...... i´m desperate, i think
Code:
// http.cpp //declarations + includes + constructors.... void CTest::RunL() { switch (iState){ case EParse:{ ParseRequestL(); SetActive(); } break; case ESent: { if(iStatus.Int() == KErrNone){ iSocket.Close(); iSent = ETrue; } } break; case ESendHTTP:{ if(iStatus.Int() == KErrNone){ iSocket.Close(); iSent = ETrue; } //it runs OK until here... the data is never sent to the servlet... SendHTTPMesg(); } break; default: break; } }
. . some auxiliar functions ... . .
void CTest::ParseRequestL() { //parses the string .... thn compares: if (code.Compare(KGetLocalPosition) == 0) { ReturnLocalDataL(); iState = ESent; } else if (code.Compare(KGetSMS) == 0) { } else if (code.Compare(KSendSMS) == 0) {
//reads from Bluetooth device (the class CModel does the reading itself via BT Sockets) void CTest::ReturnLocalDataL() { CModel* cm; cm = CModel::NewL(); cm->StartTestL(); if ((cm->iDataBuffer).Length() <= 0){ posBuffer.Copy(_L("Error. Nothind was read")); } else{ posBuffer.Copy(cm->iDataBuffer); } //this socket has nothing to do with BT Sockets... // the BT socket was closed in CModel, after reading iSocket.Write(posBuffer, iStatus); User::WaitForRequest(iStatus); TRequestStatus* status=&iStatus; User::RequestComplete(status, KErrNone);
}
//now, send the data to a server void CHTTPProtocol::DispatchDataL() { ReturnLocalDataL(); iSess.OpenL(); iTransObs = CHttpEventHandler::NewL(); RStringPool strP = iSess.StringPool(); method = strP.StringF(HTTP::EPOST,RHTTPSession::GetTable()); }
Forum posts: 723
I don't really understand your problem:
What do you mean?
Anyway, you don't have to use another thread just for this purpose. If you're concerned about multiple connections and/or multiple HTTP sessions, then a new thread will not solve your problem. The only thing you need to issue multiple HTTP requests is to use multiple RHTTPSession objects and that's all. Note that I can't see when active objects come into play here, because you can use these HTTP session without active objects: it uses callbacks, that is, you don't have to maintain request statuses, because you functions will simply called back.
tOtE
Gabor Torok
Software architect, Agil Eight (http://www.agileight.com/)
Blog: http://mobile-thoughts.blogspot.com/
Forum posts: 348
I have a series of requests (I meant requests, not connections - sorry for that) that has to be done one after another, and the next cannot start until the previous has completed.
Thanks for your reply,
Joachim
Forum posts: 1379
class CBlah : public CActive
{
enum TState
{
EState1,
EState2
}
TState iState;
};
void CBLah::RunL()
{
switch(iState)
{
case EState1:
{
iState = EState2;
// do what ever to request state 2
break;
}
case EState2:
{
break;
}
}
}
It's a very common pattern in Symbian OS programming, you should be able to find some better/more complete examples knocking about on NewLC I would think.
didster
Forum posts: 36
Forum posts: 1379
As a general rule avoid synchronous communications programming... What happens if your using the HTTP client in a synchronous way and the user presses Exit etc?? You app locks up until the current request has finished - its very ugly - and CActive solves it quite well without having to mess around with threads (in most cases anyway).
didster
Forum posts: 36
Could you justa ask one more question??
I have a CActive class that makes a bluetooth connection to read an information and then sends it to a servlet via HTTP.
When I finish tha reading from BT, I make SetActive and then in RunL I make the HTTP connection... is it OK??? The programm gets locked after reading from BT and never makes tha HTTP connection..... I´m sure its a problem whith ActiveScheduler... do you have any idea of where can be the error? Maybe tha BT reading always pending???
Forum posts: 1379
Yes - providing you keep some kind of state so you know when your RunL gets called wheather its because of your bluetooth connection, or your HTTP connection.
Put up your code if it's not working.
didster
Forum posts: 36
i´ve been trying, but.... I really don´t know how to sove the problem...
i´m gonna post my code... if someone has patience to read it., please do, I´ll be forever thankful......
i´m desperate, i think
// http.cpp
//declarations + includes + constructors....
void CTest::RunL()
{
switch (iState){
case EParse:{
ParseRequestL();
SetActive();
}
break;
case ESent: {
if(iStatus.Int() == KErrNone){
iSocket.Close();
iSent = ETrue;
}
}
break;
case ESendHTTP:{
if(iStatus.Int() == KErrNone){
iSocket.Close();
iSent = ETrue;
}
//it runs OK until here... the data is never sent to the servlet...
SendHTTPMesg();
}
break;
default:
break;
}
}
.
.
some auxiliar functions ...
.
.
void CTest::ParseRequestL() {
//parses the string .... thn compares:
if (code.Compare(KGetLocalPosition) == 0)
{
ReturnLocalDataL();
iState = ESent;
}
else if (code.Compare(KGetSMS) == 0)
{
}
else if (code.Compare(KSendSMS) == 0)
{
}
else if (code.Compare(KSetInterval) == 0)
{
}
else if (code.Compare(KSetSending) == 0)
{
}
else if (code.Compare(KSendPosition) == 0)
{
DispatchDataL();
iState = ESendHTTP;
}
else if (code.Compare(KGetIMEINumber) == 0)
{
}
else{
ReturnInvalidCode();
iState = ESent;
}
return;
}
void CHTTPProtocol::ReturnInvalidCode()
{
//not done yet
}
//reads from Bluetooth device (the class CModel does the reading itself via BT Sockets)
void CTest::ReturnLocalDataL()
{
CModel* cm;
cm = CModel::NewL();
cm->StartTestL();
if ((cm->iDataBuffer).Length() <= 0){
posBuffer.Copy(_L("Error. Nothind was read"));
}
else{
posBuffer.Copy(cm->iDataBuffer);
}
//this socket has nothing to do with BT Sockets...
// the BT socket was closed in CModel, after reading
iSocket.Write(posBuffer, iStatus);
User::WaitForRequest(iStatus);
TRequestStatus* status=&iStatus;
User::RequestComplete(status, KErrNone);
}
//now, send the data to a server
void CHTTPProtocol::DispatchDataL()
{
ReturnLocalDataL();
iSess.OpenL();
iTransObs = CHttpEventHandler::NewL();
RStringPool strP = iSess.StringPool();
method = strP.StringF(HTTP::EPOST,RHTTPSession::GetTable());
}
void CTest::SendHTTPMesg()
{
GetRequestBodyL();
TBuf8<256> url8;
url8.Copy(_L("http://some.servlet"));
InvokeHttpMethodL(url8, method);
}
void CTest::GetRequestBodyL()
{
TBuf8<12> deviceID = TBuf8<12>::TBuf8();
TBuf8<12> userID = TBuf8<12>::TBuf8();
TBuf8<14> date = TBuf8<14>::TBuf8();
TBuf<14> dateAux;
TTime time;
TDateTime dateTime;
time.HomeTime();
dateTime=time.DateTime();
TBuf8<1024> first = TBuf8<1024>::TBuf8();
TBuf8<1024> second = TBuf8<1024>::TBuf8();
first.Copy(_L("123"));
second.Copy(_L("456"));
deviceID.Copy(_L("12345678910"));
userID.Copy(_L("Name"));
GetStringDateTime(dateAux, dateTime);
date.Copy(dateAux);
if (iFormEncoder)
{
delete iFormEncoder;
iFormEncoder = NULL;
}
iFormEncoder = CHTTPFormEncoder::NewL();
iFormEncoder->AddFieldL(KIdMobile, mobileID);
iFormEncoder->AddFieldL(KLoginUser, userID);
iFormEncoder->AddFieldL(KDate, date);
iFormEncoder->AddFieldL(K1, first);
iFormEncoder->AddFieldL(K2, second);
return;
void CTest::GetStringDateTime(TDes& aBuffer,TDateTime aDateTime){
//do some data manipulation
}
void CTest::InvokeHttpMethodL(const TDesC8& aUri, RStringF aMethod)
{
TUriParser8 uri;
uri.Parse(aUri);
iTrans = iSess.OpenTransactionL(uri, *iTransObs, aMethod);
RHTTPHeaders hdr = iTrans.Request().GetHeaderCollection();
SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);
SetHeaderL(hdr, HTTP::EAccept, KAccept);
TBuf8<KMaxContentTypeSize> contTypeBuf;
contTypeBuf.Copy(_L("application/x-www-form-urlencoded"));
RStringF contTypeStr = iSess.StringPool().OpenFStringL(contTypeBuf);
THTTPHdrVal contType(contTypeStr);
hdr.SetFieldL(iSess.StringPool().StringF(HTTP::EContentType,RHTTPSession::GetTable()), contType);
contTypeStr.Close();
MHTTPDataSupplier*dataSupplier = iFormEncoder;
iTrans.Request().SetBody(*dataSupplier);
iTrans.SubmitL();
}
void CTest::SetHeaderL(RHTTPHeaders aHeaders, TInt aHdrField, const TDesC8& aHdrValue)
{
RStringF valStr = iSess.StringPool().OpenFStringL(aHdrValue);
THTTPHdrVal val(valStr);
aHeaders.SetFieldL(iSess.StringPool().StringF(aHdrField,RHTTPSession::GetTable()), val);
valStr.Close();
}
//event handler
void CHttpEventHandler::ConstructL(){}
CHttpEventHandler::CHttpEventHandler() {}
CHttpEventHandler::~CHttpEventHandler(){}
CHttpEventHandler* CHttpEventHandler::NewLC()
{
CHttpEventHandler* me = new(ELeave)CHttpEventHandler();
CleanupStack::PushL(me);
me->ConstructL();
return me;
}
CHttpEventHandler* CHttpEventHandler::NewL()
{
CHttpEventHandler* me = NewLC();
CleanupStack::Pop(me);
return me;
}
void CHttpEventHandler::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
{
switch (aEvent.iStatus)
{
case THTTPEvent::EGotResponseHeaders:
{
RHTTPResponse resp = aTransaction.Response();
TInt status = resp.StatusCode();
if (status != 200){
aTransaction.Close();
}
else{
RStringF statusStr = resp.StatusText();
TBuf<32> statusStr16;
statusStr16.Copy(statusStr.DesC());
}
} break;
case THTTPEvent::EGotResponseBodyData:
{
} break;
case THTTPEvent::EResponseComplete:
{
} break;
case THTTPEvent::ESucceeded:
{
aTransaction.Close();
} break;
case THTTPEvent::EFailed:
{
aTransaction.Close();
} break;
case THTTPEvent::ERedirectedPermanently:
{
} break;
case THTTPEvent::ERedirectedTemporarily:
{
} break;
default:
{
if (aEvent.iStatus < 0)
{
aTransaction.Close();
}
} break;
}
}
TInt CHttpEventHandler::MHFRunError(TInt aError, RHTTPTransaction /*aTransaction*/, const THTTPEvent& /*aEvent*/)
{
return KErrNone;
}
thanks!!!!