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.
User::LeaveIfError(listener.Open(socketServ, KAfInet,KSockStream, KProtocolInetTcp));
“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.
//… assign value to msglen …
HBufC8* buffer = HBufC8::NewL(msglen);
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];
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.