If your network Symbian program just blocks forever mysteriously, or you just want a simple piece of code to demonstrate how to use socket in Symbian. This story is for you.
Very often, we want to read a given number of bytes from a network when, for example, the message body length is known after reading the header. Symbian
RSocket provides two groups of reading methods,
RecvOneOrMore() with a scheme for reading some and returning as soon as possible and
Read() with a scheme for blocking until the maximum length of the buffer descriptor is fully filled. Both the schemes can fulfill our requirement. With
RecvOneOrMore, we can make a loop to keep reading and counting the returned bytes until the sum is not less than the desired message length. Obviously, this method is not efficient enough. We may prefer to allocate a descriptor with a given maximum length and use
Read() to get the work done in one call. The example is as follows:
listener object listens at port 80, once an incoming connection is accepted; another
socket reads the data from the network as shown in the last three lines. Here, 256 bytes are read before the code can continue.
This is not the end of the story because while we are coding, we usually have no idea if it must be 256. The number of bytes to be read can be known only at run time. But the size of the stack based descriptor
TBuf must be set before compilation. Unfortunately, I couldn't find any piece of example code that solves this problem in SDK document or Google. I tried to use the 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 using the method
HBufC::Des(). This gives a good introduction to the Symbian descriptor system. The code is modified as follows:
HBufC8* buffer = HBufC8::NewL(msglen);
It works as expected. But is it correct? I thought so before it took me a whole day to find out why sometimes the program just blocks forever. For example, when the value of
msglen is 137 and when you check
buffer->Des().MaxLength() of the newly allocated
buffer, you get a value of 140! The
RSocket::Read method checks only the MaxLength and tries to fill it. It keeps waiting for the 3 bytes that never exist even when the desired 137 bytes have already been received.
Why the MaxLength is 140 and not 137? 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 descriptor-tips says. The size of the heap cell only guarantees that it can contain the size given by the user, but not equal to it! 137 is not word-aligned, so the system allocates 140 instead.
I can’t imagine that the Symbian descriptor system doesn’t provide any solution for such a simple problem to the
RSocket::Read’s requirement. However, I am too exhausted to dig for it. I finally chose a non-Symbian favour by maintaining a C-style array.
TUint8 *buf=new TUint8[msglen];
Of course, now I have to take care of releasing the array space myself.
I'll appreciate if any Symbian expert can 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.