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

ntroduction

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.

The expedition

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 Recv()/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 Recv()/Read() to get the work done in one call. The example is 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);
......

The listener object listens at port 80, once an incoming connection is accepted; another RSocket object 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:

    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 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];
gDataPtr.Set(buf,0,msglen);
blank.Read(gDataPtr,status);
User::WaitForRequest(status);

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.

<script src="http://www.codeproject.com/script/togglePre.js" type="text/javascript"></script>  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值