prob with active objects .. for TCP sockets ..
| Wed, 2003-09-17 13:53 | |
|
Hi All ,
I was writing a test code for testing TCP sockets active and passive connection . I have two active objects created and both binded two different ports on same IP address ( 127.0.0.1 ) one object (Passive) ilistens .. and other object (active) connects with port address of passive one . both connect and listen done during the construction of each objects. when i test this code .. the prob is .. the RUNL of only one active objects is called at ONE time . RUNL of other is not called at all.. Listen request of Passive completes and in RUNL of Passive is called where my accept request completes successfully . BUT RUNL of Active is never called ( which should be called when Connect Request Completes) and if increase priority of active then passive RUNL is not called ... Where ia m going wrong .. Please see the Code.. Thanks in Adv... Puneet . Code: Passive AO::Open(src_ip,src_port) { ... err=iSession.Connect(); User::LeaveIfError(err); err = iListen.Open(iSession, KAfInet,KSockStream, KProtocolInetTcp); User::LeaveIfError(err); //blank socket err = iSocket.Open(iSession); User::LeaveIfError(err); // Bind the listening socket to the required // port. TInetAddr Addr_Passive(src_ip, src_port); iListen.Bind(Addr_Passive); // Listen for incoming connections... iListen.Listen(2); SetActive(); ..Passive RUNL code ... { .... iListen.Accept(*iSock, iStatus); User::WaitForRequest(iStatus); ... } Active Object::Open(.....) { iSocket = new RSocket(); CActiveScheduler::Add(this); err=iSession.Connect(); User::LeaveIfError(err); err = iSocket->Open(iSession, KAfInet,KSockStream, KProtocolInetTcp); User::LeaveIfError(err); TInetAddr Addr_Active_Dest(dest_ip,dest_port); iSocket->Connect(Addr_Active_Dest,iStatus); SetActive(); } Active AO RUNL... { // which is never called... } ... Test Code ...//Main function { //Construct Passive instance then cal.. passiveconn->open //construct Active instance then call.. ActiveConn->Open //issuing connect request here //NOW after this i start ActiveScheduler } |
|






Forum posts: 363
Looking at the code, your active objects are not implemented properly - see the Symbian Programming books for more information on this.
At least the RunL methods and the Test Code look like they are causing the problems.
Cheers,
Pawel
Forum posts: 4
i'll confirm My implementation again ..
..but cud u please just review these steps which i am trying to achieve .. and let me know if there is something fundamentally wrong in these steps .
1)I construct one active object (say A) add it to scheduler and Issue request for Listening on this Active object. calls SetActive() for this Active Object
2)Construct another active object (say B) add it to Scheduler and issue request for Connect on this object . Call SetActive
3) Now I start Active Scheduler .At this point i Feel two request are oustanding and expects active sheculer to schedule the RunL metthods of both the objects (CAN I DO this??)
4) The execution reaches my RunL of active object A , with iStatus as KerrNone , then in this RunL I just Call Accept method Synchronously , which completes immiediately . and Runl Returns ..
5) Now i expect Runl of Active object B should be called BUT i Does NOT get called ..
Do you think something is wrong in implementing this ?? and it should be achievable ..
Puneet
Forum posts: 3
Forum posts: 31
But you did not seem to have issued a request for your passive active object. According to my experiences (basic trial and error, and struggling to understand the documentation), you need to issue a request in a function (which is not the RunL() function), in order for RunL() to be executed.
Hence what I usually do is to have a Start() function...
void Start()
{
some_request(..., iStatus);
SetActive();
}
and then, RunL() will be executed without any trouble...
Forum posts: 4
Actually I am issuing the request in Passive::open function and Active Open function .. which is Listen() ... and Connect Resp .. and infact Runl of Pasive is executed . the Runl of Active is not getting executed .. or you can say . with issuing two request .. only one of the RunL gets executed ..
I tried even with changing priority to idle also..
But you did not seem to have issued a request for your passive active object. According to my experiences (basic trial and error, and struggling to understand the documentation), you need to issue a request in a function (which is not the RunL() function), in order for RunL() to be executed.
Hence what I usually do is to have a Start() function...
void Start()
{
some_request(..., iStatus);
SetActive();
}
and then, RunL() will be executed without any trouble...
Forum posts: 723
There are few things you misunderstood.
First, RSocket::Listen is not an asynchronous call. Thus, it's meaningless to call SetActive right after invoking Listen. This method is a synchronous one and as such you can simply continue your code with preparing for a call to RSocket::Accept.
Second, you might ask : if Listen is not an asynchronous call, then why its RunL is called? Well, I have two remarks on this :
- you do not have to call an asynchronous service in order to get your RunL called by the AS (active scheduler). You simply have to assign KRequestPending to your iStatus and call SetActive and after that your RunL will be called some time.
- I realized that you did not change your request status, thus your RunL should not have been called at all. It is surprising to me, I can't help on this.
Third, do not forget that calling User::WaitForRequest should not be the preferred solution as it blocks the whole thread.
Fourth, you did not mention whether your active socket's (i.e. that wants to connect to another socket) Open method leaves or not. It might be questionable, because if your iSession member is the same RSocketServ object (is it an RSocketServ at all?) that is used by the other sockets, then calling RSocketServ::Connect the second time will result in a failure. Thus, your active socket's Open will leave as you issued a User::LeaveIfError.
Finally, If I were you I'd implement this as follows :
{
// prepare listening socket
// ...
iListeningSocket.Listen(1);
// preparing blank socket
// ...
iBlankSocket.Open(...);
// now issue the real asynchronous request
iListeningSocket->Accept( iBlankSocket, iStatus );
SetActive();
}
Passive AO::RunL()
{
if ( iStatus.Int() == KErrNone )
{
RDebug::Print( _L( "Hail" ) );
}
else
{
RDebug::Print( _L( "Damn" ) );
}
}
Active AO::OpenL()
{
// Prepare the socket for connection establishment
// ...
iActiveSocket.Connect(...);
SetActive();
}
Active AO::RunL()
{
if ( iStatus.Int() == KErrNone )
{
// Change internal state, notice that the connection is established,
// do whatever you want
}
else
{
RDebug::Print( _L( "Damn" ) );
}
}
Hope it helps,
tOtE
Gabor Torok
Software architect, Agil Eight (http://www.agileight.com/)
Blog: http://mobile-thoughts.blogspot.com/
Forum posts: 4
this was very helpfull for me to understand some concepts which i misunderstood, ..but in general I have some comments
>the reason for me using ACCEPT call in side Runl was I expect multiple active clients may request this passive clients for connection . For which i understand we will need to call accept again with new blank socket and listen should not be called again . But i had a feel there is something wrong in this . can you tell what could be better way of handling multiple connection requests to same server. I am not sure If we can reuse same blank socket again , after storing the handle maried to this blank socket in some other socket ( does this make sense???) ...
Also i have one more question with Active Scheduler. It is stated in system docs ..
""At least one active object, with an outstanding request, must be added to the scheduler before the wait loop is started, otherwise no events will occur and the thread will hang or any events that do occur will be counted as stray signals, raising a panic. """
Why this requirement ?? .. and does that mean in whole life of active scheduler there should be always atleast one outstanding request pending ??
thanks
Puneet
There are few things you misunderstood.
First, RSocket::Listen is not an asynchronous call. Thus, it's meaningless to call SetActive right after invoking Listen. This method is a synchronous one and as such you can simply continue your code with preparing for a call to RSocket::Accept.
Second, you might ask : if Listen is not an asynchronous call, then why its RunL is called? Well, I have two remarks on this :
- you do not have to call an asynchronous service in order to get your RunL called by the AS (active scheduler). You simply have to assign KRequestPending to your iStatus and call SetActive and after that your RunL will be called some time.
- I realized that you did not change your request status, thus your RunL should not have been called at all. It is surprising to me, I can't help on this.
Third, do not forget that calling User::WaitForRequest should not be the preferred solution as it blocks the whole thread.
Fourth, you did not mention whether your active socket's (i.e. that wants to connect to another socket) Open method leaves or not. It might be questionable, because if your iSession member is the same RSocketServ object (is it an RSocketServ at all?) that is used by the other sockets, then calling RSocketServ::Connect the second time will result in a failure. Thus, your active socket's Open will leave as you issued a User::LeaveIfError.
Finally, If I were you I'd implement this as follows :
{
// prepare listening socket
// ...
iListeningSocket.Listen(1);
// preparing blank socket
// ...
iBlankSocket.Open(...);
// now issue the real asynchronous request
iListeningSocket->Accept( iBlankSocket, iStatus );
SetActive();
}
Passive AO::RunL()
{
if ( iStatus.Int() == KErrNone )
{
RDebug::Print( _L( "Hail" ) );
}
else
{
RDebug::Print( _L( "Damn" ) );
}
}
Active AO::OpenL()
{
// Prepare the socket for connection establishment
// ...
iActiveSocket.Connect(...);
SetActive();
}
Active AO::RunL()
{
if ( iStatus.Int() == KErrNone )
{
// Change internal state, notice that the connection is established,
// do whatever you want
}
else
{
RDebug::Print( _L( "Damn" ) );
}
}
Hope it helps,
tOtE
Forum posts: 723
I think it is still enough to use
Blank sockets : well, I have not done things like that earlier, but my opinion is as follows. You use a blank socket, because you do not know the characteristics of a remote socket in advance. When the two sockets (i.e. local and remote) are coupled, your local (and hitherto blank) socket is configured by the remote socket. After the connection is set up, it is no more a blank socket. Thus, in order to make it possible to listen (and accept) to new incoming connection requests, you have to create another blank socket and pass it to iListeningSocket's Accept method.
Example : you are a server, peering for incoming connections and maintaining current connections simultaneously. Assume that there are three established connections. What is the situation with sockets?
1 listening socket, it is pending (RSocket::Accept has not yet completed),
1 blank socket, it is passed to the listening socket,
3 properly configured sockets that are the local end-points of the connections currently "running".
Finally, AS : well, I do not fully understand the mechanism of it either, but after reading the documentation (and as I've got a few years experience) I think it is done as follows.
The AS is interested in various events, thus it issues a User::WaitForAnyRequest. This request blocks the thread (I'm not sure about this, however), so nothing can be done meanwhile, only if an AO is completed. Don't forget that the program execution is nothing else, but running AOs' RunL method, one after the other. If something happens in your program, it will always be in an AO's RunL. Thus, the AS's User::WaitForAnyRequest completes only when an AO's state changes. If there are no AOs in the AS's queue, then it will never be possible to add a new (i.e. the very first) AO as the whole thread is blocked. If User::WaitForAnyRequest happened to complete, but there is no appropriate AO in the AS's queue, then a stray signal occurs, which results in a panic in the current thread.
That's all!
tOtE
Gabor Torok
Software architect, Agil Eight (http://www.agileight.com/)
Blog: http://mobile-thoughts.blogspot.com/
I tried change the priority and did not work.....
Any suggestions???
That´s the code:
SERVER:
......
void CBlal::StartTestL()
{
StartConnection();
SetActive();
}
void CBlal::StartConnection(){
TInt err;
TInetAddr httpPort(KInetAddrLoop, 80);
err=ss.Connect();
User::LeaveIfError(err);
err = iSocket.Open(ss, KAfInet, KSockStream, KUndefinedProtocol);
User::LeaveIfError(err);
err = iConnection.Open(ss);
User::LeaveIfError(err);
err = iSocket.Bind(httpPort);
iSocket.Listen(1);
iSocket.Accept(iConnection, iStatus);
User::WaitForAnyRequest();
iChannelState = EChannelListening;
if (iStatus == KErrNone){
console->Printf(_L("Ouvindo conexão aceita \n"));
}
else{
console->Printf(_L("Problems \n"));
console->Printf(_L("Error: %d\n"),iStatus);
}
}
......
CLIENT:
......
void CModel::StartTestL()
{
TInt err;
TInetAddr localLoop(KInetAddrLoop, 80);
RSocketServ ss;
err=ss.Connect();
User::LeaveIfError(err);
console->Printf(_L("CREATING socket TCP...\n"));
err = iSocket.Open(ss, KAfInet, KSockStream, KUndefinedProtocol);
User::LeaveIfError(err);
console->Printf(_L("Connecting....."));
iSocket.Connect(localLoop, iStatus);
User::WaitForAnyRequest();
console->Printf(_L("OK!\n"));
iChannelState=EChannelSending;
SetActive();
}
none of the two RunL functions are called after SetActive!!!!!! Why?