65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 RSocket::Read() 读取给定字节数

starIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIconemptyStarIcon

1.50/5 (3投票s)

2005年7月14日

CPOL

3分钟阅读

viewsIcon

35777

探索如何在 Symbian 上使用 RSocket::Read() 读取指定数量的字节。

引言

如果你的网络 Symbian 程序总是神秘地无限期阻塞,或者你只是想要一段简单的代码来演示如何在 Symbian 中使用套接字,那么这篇文章就是为你准备的。

探索之旅

很多时候,我们需要从网络读取指定数量的字节,例如,在读取消息头后知道消息体长度。Symbian RSocket 提供了两组读取方法,RecvOneOrMore() 方案是读取一些数据并尽快返回,而 Recv()/Read() 方案是阻塞直到缓冲区描述符的最大长度被完全填满。这两种方案都可以满足我们的需求。使用 RecvOneOrMore,我们可以创建一个循环来不断读取并计数返回的字节,直到总和不小于所需的消息长度。显然,这种方法效率不够高。我们可能更喜欢分配一个具有给定最大长度的描述符,并使用 Recv()/Read() 在一次调用中完成工作。示例如下

    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 对象监听端口 80,一旦接受传入连接,另一个 RSocket 对象 socket 从网络读取数据,如最后三行所示。在这里,读取 256 个字节后,代码才能继续执行。

故事还没结束,因为在编写代码时,我们通常不知道它必须是 256。要读取的字节数只能在运行时知道。但是基于栈的描述符 TBuf 的大小必须在编译之前设置。不幸的是,我在 SDK 文档或 Google 中找不到任何解决此问题的示例代码。我尝试使用基于堆的替代方案 HBufC,其大小可以在运行时设置。HBufC 是不可修改的。但是 RSocket::Read 方法需要一个可修改的描述符。这可以通过使用方法 HBufC::Des() 来克服。这个 对 Symbian 描述符系统进行了很好的介绍。代码修改如下

    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);

它按预期工作。但它正确吗?我以前是这么想的,直到我花了一整天的时间才弄清楚为什么有时程序会无限期阻塞。例如,当 msglen 的值为 137 时,当你检查新分配的 bufferbuffer->Des().MaxLength() 时,你会得到 140 的值!RSocket::Read 方法只检查 MaxLength 并尝试填充它。它一直在等待永远不会存在的 3 个字节,即使已经接收到所需的 137 个字节。

为什么 MaxLength 是 140 而不是 137?因为“用于分配 HBufC 的堆单元的最大长度用于设置返回的 TPtr 的最大长度”,如 descriptor-tips 的 Tip9 所述。堆单元的大小只保证它可以包含用户给定的大小,但不等于它!137 没有字对齐,因此系统分配了 140。

我无法想象 Symbian 描述符系统没有为 RSocket::Read 的要求提供任何解决这样一个简单问题的方法。但是,我太疲惫了,无法深入挖掘它。我最终选择了一种非 Symbian 的方式,即维护一个 C 风格的数组。

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

当然,现在我必须自己负责释放数组空间。

如果任何 Symbian 专家能给我们一个官方解决方案,我将不胜感激。我的探索必须在这里停止,否则我忍不住要删除我的 Symbian SDK 并安装双份的 Java 和 .NET 了。

© . All rights reserved.