×

Discussion Board

Results 1 to 2 of 2
  1. #1
    Registered User
    Join Date
    Jul 2005
    Posts
    1

    Exclamation Reading given number of bytes with RSocket::Read()

    Frequently, we want to read given number of bytes from the network when, for example, a message body length has been known after reading the header. Symbian RSocket gives two groups of reading methods, RecvOneOrMore() with scheme of reading some and returning as soon as possible and Recv()/Read() with scheme of blocking until maximum length of buffer descriptor has been fully filled. Both schemes can fulfill our requirement. With the RecvOneOrMore, we can make a loop to keep reading and counting the returned bytes until the sum is no less than desired message length. Obviously, it could be not efficient enough. We may prefer to allocate a descriptor with given maximum length and use Recv()/Read() to make the work done in one call. The example can be as follows.

    RSocketServ socketServ;
    RSocket socket;
    RSocket listener;
    User::LeaveIfError(socketServ.Connect());
    CleanupClosePushL(socketServ);
    User::LeaveIfError(listener.Open(socketServ, KAfInet,KSockStream, KProtocolInetTcp));
    User::LeaveIfError(listener.SetLocalPort(80));
    User::LeaveIfError(listener.Listen(1));
    TRequestStatus status;
    TBuf8<256> buffer;
    socket.Open(socketServ);
    listener.Accept(socket, status);
    User::WaitForRequest(status);
    ……
    TBuf8<256>data;
    socket.Read(data,status);
    User::WaitForRequest(status);
    ……

    “listener” object listens at port 80, once an incoming connection is accepted, another RSocket object “socket” is ready to read data from the network as in the last three lines. Here, 256 bytes will be read before the code can continue.
    This is not the end of the story because when we are coding, we usually have no idea if it must be 256. The number of bytes to be read can be only known at run time. But the size of stack based descriptor TBuf must be set before compile. Unfortunately, I fail to find any piece of example code to solve this problem in SDK document or Google. Reasonably, I tried to use heap based alternative, HBufC, whose size can be set at run time. HBufC is not modifiable. But RSocket::Read method requires a modifiable descriptor. This can be overcome by method HBufC::Des(). http://descriptors.blogspot.com/2005...escriptor.html gives good introduction of Symbian descriptor system. The code is modified as follows.

    TPtr8 gDataPtr(NULL,0);
    UInt32 msglen;
    //… assign value to msglen …
    HBufC8* buffer = HBufC8::NewL(msglen);
    gDataPtr.Set(buffer->Des());
    socket.Read(gDataPtr,status);
    User::WaitForRequest(status);

    It works as we expect. But is it correct? I did think so before it took me a whole day to find out why sometimes the program just blocked forever. For example, when the value of “msglen” is 137 and if you check “buffer->Des().MaxLength()” of the newly allocated “buffer”, you will get 140! The RSocket::Read method only checks the MaxLength and trys to fill it. It keeps waiting for the further 3 bytes that never exist even the desired 137 bytes have been already received.
    Why the MaxLength is 140 but 137 as we ask for? Because “the maximum length of the heap cell in which the HBufC was allocated is used to set the maximum length of the returned TPtr.” as Tip9 of http://descriptor-tips.blogspot.com/ says. The size of the heap cell only guarantees that it can contain the size given by user, but not equal to! 137 is not word-aligned, so the system allocates 140 instead.
    I can’t imagine the Symbian descriptor system doesn’t provide a solution for such a simple problem to satisfy the RSocket::Read’s requirement. However I’ve been already too exhausted to dig for it. I finally choose a non-Symbian favour by maintaining a C-style array.

    TUint8 *buf=new TUint8[msglen];
    gDataPtr.Set(buf,0,msglen);
    blank.Read(gDataPtr,status);
    User::WaitForRequest(status);

    Of course I have to take care of releasing the array space myself now.
    I very appreciate if any Symbian experts give us an official solution. My expedition has to stop here before I can’t help deleting my Symbian SDK and install double copies of Java and .NET.

  2. #2
    Regular Contributor
    Join Date
    Apr 2005
    Posts
    89
    I think it's better for you to delete Symbian SDK and install Java if you cannot find a solution to such a simple problem. Java it much more novice-friendly although I feel I became more stupid every time I program it too much. Anyway here're some hints:

    1. You already found this, but you could save sime time by reading HBufC description beforehand:
    It is important to note that the size of the allocated cell, and, therefore, the resulting maximum length of the descriptor, may be larger than requested due to the way memory is allocated in Symbian OS. The amount by which this may be rounded up depends on the platform and build type.
    You should also beware of this when reading from files etc.

    2. Actual solution #1:
    Code:
    UInt32 msglen;
    //… assign value to msglen …
    HBufC8* buffer = HBufC8::NewL(msglen);
    TPtr8 gDataPtr(&buffer->Des()[0], msglen);
    socket.Read(gDataPtr,status);
    User::WaitForRequest(status);
    3. Actual solution #2: subclass TDes8 or TPtr8 with something returning any MaxLength() and MaxSize() values you want.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •