BREW网络和套接字指导原则

海思MIPI屏调试实战:从参数计算到点亮屏幕的完整指南 本文提供了一份海思平台MIPI屏幕调试的完整实战指南。文章以Hi3516DV300调试800x1280分辨率屏幕为例,详细讲解了从参数计算、配置文件修改到最终点亮屏幕的全流程,并分享了常见问题排查与进阶优化技巧,旨在帮助嵌入式开发者高效解决MIPI屏调试难题。 阅读详情
网络和套接字指导原则
2003年9月12日  作者:高通  移动锋行  

线程问题

开发者在 Windows 或 Unix 平台上的应用程序中使用网络时通常使用编块调用。此类调用只有在操作完成或失败时才返回。例如,通常会使用编块写入调用。它只有在所有数据成功发送或出错时才会返回。同样,许多程序员对编块套接字使用 fgets() 等调用。在接收到完全行前它会等待。

对于本地 I/O(如磁盘读写),编块套接字类似于编块调用,因此被广泛使用。但是,与本地磁盘 I/O 不同,网络会继承性地受到不可预见的延迟的制约。这些延迟在执行任何操作时都可能发生,而且可能持续几分钟时间。

要防止某应用程序被锁定且在编块时不响应用户事件或其它事件,开发者一般会使用线程;通常,每个网络连接一个线程。就象使用编块调用一样,线程具有熟悉的线性范型的优点,但会增加开销和复杂性。除了内存和其它系统资源,线程还会使用不太明显的资源,如用于维持状态、同步等的结构空间。线程会极大地增加应用程序的复杂性,从而增加代码和内存。应用程序越复杂,出现故障的几率也就越高。线程会在访问共享对象时引起同步问题。仅此领域就有很多陷阱。

BREW™ 的回调不编块策略在一种考虑使用更简单程序的模型中提供等效功能,因此更容易写入和调试(因而更加稳定),而且使用的资源更少。

因为 BREW 不支持线程,BREW API 更加简单(创建、销毁、启动、停止和同步线程时不需要调用)。BREW 层本身更小、更高效且更简单(因此更可靠)。这样,将 BREW 移植到新的芯片集和手持设备时就会缩短所需时间、降低所需成本、节省所需精力。

应用程序(在很多情况下,BREW 层本身)会通过避免各种多线程问题而受益。问题包括:

  1. 对共享数据的多线程访问导致极难察觉的故障

  2. 难以(或无法)充分测试多线程代码,尤其是在跨开发环境中

  3. 堵塞在编块调用中的线程的响应性问题 - 通常这些情况中的某些情况被忽视,因此,线程(依次为应用程序)无法不经某些随意的延迟而安全终止。这是移动手持设备资源严格受限的环境中存在的问题。

一般来说,不编块实施使用的内存更少(尤其包括栈内存),而且处理中断更加容易和简洁。

与不编块 API 相关的一个潜在困难包括处理为编块 API 编写的大块现有代码。不过,任何编块网络代码可以“机械地”转换成不编块版本。它不是当前有软件执行此操作意义上的机械,而是进程可以体现在象编译器一样复杂的软件中意义上的机械。转换过程可能十分耗时,但是如果开发者清楚地理解并重视基本的等效概念,则即使是较大的代码库也可以成功进行转换。


转换不编块代码

转换过程使用面向对象术语进行描述,但可以根据需要用 C 或 C++ 实施。

每个编块函数 - 即直接或间接等待外部事件的函数 - 可以转换为有三个或三个以上方法的对象(成员函数):

  1. 构造函数

  2. 析构函数

  3. 功函数

以下操作应该可以确保有效转换:

  1. 定义一个有持久状态的对象/结构。寿命跨编块操作的所有有值本地变量必须移动到该对象(这可能包括原始函数的变量)。因为该对象在堆上分配,其成员会在返回控制权时仍然存在。

  2. 创建一个“新”函数来分配和初始化状态对象。该函数以传递到原始编块函数的参数为参数。它还有两个描述在完成时调用的回调函数的两个新参数(函数指针和空指针)。

  3. 创建一个“功”函数,包含原始编块函数的主要部分。它有一个参数:状态对象的指针。功函数由构造函数调度或调用。

    功函数是一个状态机:它使用当前状态值来执行开关语句。它包含每个状态的情况语句标记。由原始代码中的编块调用分隔的每个操作系列有一个状态(和其它似乎有用的状态)。

    调用时,功函数会继续处理原始函数的任务,直到它必须等待事件时为止(例如完成网络连接)。然后,它会保存对象中的状态,请求从适当的机制中回调并返回。再次调用时,它会从上次停止的位置继续(使用对象中存储的状态值作为其开关语句的索引)。这要求对函数的主要部分进行以下修改:

    1. 每个编块调用被启动异步操作、调度功函数自身以在完成时重新调用、记录当前状态并将控制权返回调用程序的代码序列替换。每个状态都有一个情况语句标记。

      例如:

          WaitOnKeypress();
              

      变成:

          KeypressNotify ( me, Object_Work );
          me->nState = ST_WAITFORKEY;
          return;
              

      通知回调函数与功函数的原型不匹配的情况下,可以使用一个较小的助手函数。该助手函数与通知回调函数原型匹配,仅调用功函数。例如,向 BREW Connect() 回调函数传递结果值。助手函数可以在状态对象中存储结果值并调用功函数。

    2. 每个以前编块的调用都被赋予了一个状态值。在功函数开始处,使用状态变量的开关将控制流导向相应的标记。根据情况,可以只让开关语句对每个状态执行一个 goto 语句。这可以使您保持编块代码的原始结构(包括“for”和“while”循环)。不过,将代码移动到开关语句一般更容易进行保持和验证。(如果一个情况语句的代码较长,您可以将其移至 INLINE 函数。)

      示例:

          switch ( me->nState )
          {
              ...
              case ST_WAITFORKEY:
                  ...
      break;
              ...
          }
              
    3. 功函数通常在事件完成时由 BREW 调用,而原始函数仅在原始应用程序执行流程中被调用。因此,功函数会调用一个回调函数来通知其客户端(“调用程序”),而不是退出将控制权返回调用程序并恢复原始控制流(如编块函数)。如果原始函数返回一个值,最好通过向构造函数传递一个结果存储位置的指针来处理。

  4. 一个“delete”函数会销毁该对象 - 在任何时候停止操作 - 释放分配的所有资源并取消可能已调度的任何操作。该函数也应该由功函数调用,以在调用客户端回调函数前清除任何资源。

    因为 BREW 没有线程和可重入功能,delete 函数仅可在功函数未激活时由客户端调用(已调度回调函数并退出)。这样就简化了 delete 和功函数,因为功函数不需为执行取消操作而锁定任何内容或进行测试,而 delete 函数仅须清除(包括取消功函数请求的回调函数)和释放资源。

    客户端(原始调用程序)可能会响应按“取消”按钮的用户,直接调用 delete 函数,中途中断操作。


转换示例

下面是一个转换示例。颜色表示原始函数的某些关键组成部分以及在新版本中的相应部分。

  • 持久变量(绿色)

  • 编块/不编块调用转换(蓝色)

  • 不编块版本的新变量/代码(红色)


原始编块版本:

下面是一个执行时间较长的简单编块函数。它省略了一些“#define”和错误检查并隐藏了许多无关的功能。一个“空”函数简化了该示例。(有返回值的函数首先应转换成空函数。)

    void QueryDNS (const char *pszDomain, INAddr *paddrResult )
    {
        char *pcReq      = NULL;
        int   cbReq      = 0;
        int   cntTries   = 0;
        int   s          = socket();
        int   nRcvd      = 0;
        char  buf [ 512 ];
        pcReq = malloc ( 300 );
        cbReq = DNSConstructRequest ( pcReq, pszDomain );
        do
        {
            INAddr addr;
            INPort port;
            sendto ( s, DNSADDR, DNSPORT, pcReq, cbReq );

            // recvfrom_timeout: 假定的阻塞函数,
            // 与 recvfrom() 类似,但有明确的超时值

            nRcvd = recvfrom_timeout ( s, &addr, &port, 3000,
                                       buf, sizeof(buf) );
        }
            while ( nRcvd == TIMEOUT && ++cntTries < MAXTRIES );
        if ( nRcvd > 0 )
        {
            *paddrResult = DNSReadResult ( buf, nRcvd );
        }
#else
        {
            *paddrResult = INADDR_NONE;
        }
    free  ( pcReq );
    close ( s );
    }


结果:

结果是下面的类定义(此处使用了具有面向对象约定的 C 代码)。使用了 goto 形式,而不是将代码嵌入 switch 语句,因为它要求继续使用更多的原始控制流(包括循环),因此更清楚地对转换进行了例示。不过,如果不使用 goto 而将代码移至 switch 语句将更加简洁,而且更容易维护和调试。

注意:还有待于执行许多明显的优化操作(例如,可以通过将状态 0 功函数移至 New 函数取消状态变量和开关、两个内存分配可以合并为一个、可以取消某些持久变量)。因为本例用于说明转换过程的一致性,这些优化操作可以省略。

对于异步套接字操作,使用完成时回调接口,而不是 BREW 套接字 API 的准备重试时回调接口,以说明更具有一般性的情况。不过,差异较小。

typedef struct
    {
int               nState;
        CLIENT_CALLBACK  *pAllDone;
        void            **ppClientPtr;
char             *pcReq;
        int               cbReq;
        int               cntTries;
        INAddr           *paddrResult;
        int               nRcvd;
        int               s;
        char              buf [ 512 ];
    } QueryDNS;

    // 创建对象;此处包含所有的初始化代码
    //

    QueryDNS *QueryDNS_New ( const char       *pszDomain,
                             INAddr           *paddrResult,
                             CLIENT_CALLBACK  *pAllDone,
                             void            **ppClientPtr )
    {
        QueryDNS *me = (QueryDNS *) malloc ( sizeof(QueryDNS) );
        me->pcReq       = malloc ( 300 );
        me->cbReq       = DNSConstructRequest ( me->pcReq,
                                                pszDomain );
        me->cntTries    = 0;
        me->nState      = 0;
        me->paddrResult = paddrResult;
        me->pAllDone    = pAllDone;
        me->ppClientPtr = ppClientPtr;
        me->s           = socket();
        QueryDNS_Work ( me );
    }

    // 删除对象;此处包含所有的清除代码
    //
    QueryDNS_Delete ( QueryDNS *me )
    {
        // recvfrom_timeout_cancel() 和 sendto_cancel 是假定的

        // 取消接收和发送操作的函数。
        recvfrom_timeout_cancel ( me, QueryDNS_Work );
        sendto_cancel ( me, QueryDNS_Work );
        close ( me->s );
        free  ( me->pcReq );
        free  ( me );
    }
    void QueryDNS_Work ( void *pvCxt )
    {
        // 创建 pvCxt 的转换变量,从而便不

        // 必转换 Work() 函数指针
        QueryDNS *me = (QueryDNS *) pvCxt;
        switch ( me->nState )
        {
            case 1:
                goto querydns_st_1;
            case 2:
                goto querydns_st_2;
         // case 0: 失败
        }
        do
        {
            INAddr addr;
            INPort port;
            sendto_asynch ( me->s, DNSADDR, DNSPORT, pcReq, cbReq,
                            me, QueryDNS_Work );
            me->nState = 1;
            return;
    querydns_st_1:

            // recvfrom_timeout_asynch: 假定的调用
            // 成功或超时后调用的函数
            recvfrom_timeout_asynch ( me->s, &addr, &port, 3000,
                                      me->buf, sizeof(me->buf), &me->nRcvd,
                                      me, QueryDNS_Work );
            me->nState = 2;
            return;
    querydns_st_2:
        }
            while ( me->nRcvd == TIMEOUT && ++cntTries < MAXTRIES );
if ( me->nRcvd > 0 )
        {
            *me->paddrResult = DNSReadResult ( me->buf, me->nRcvd );
       }
else
        {
            *me->paddrResult = INADDR_NONE;
        }
        me->pAllDone ( me->ppClientPtr );
        QueryDNS_Delete ( me );
    }


用法差异:

调用程序不调用 QueryDNS() 并期望它返回时结果有效,而是使用:

    me->pqdns = QueryDNS_New ( pszDomain, &me->addr,
                               me, MyObj_DNSDone );

调用 MyObj_DNSDone() 时,me->addr 保存结果。最后,调用程序应正确支持操作的取消。这包括:

  1. 调用回调函数时将 me->pqdns 设置为 NULL

  2. 取消时,执行以下操作:

    if ( me->pqdns != NULL )
        {
            QueryDNS_Delete ( me->pqdns );
            me->pqdns = NULL;
        }
        

为了获得额外安全,可以向 QueryDNS_Delete() 函数传递 me->pqdns 的地址,从而可以将它设置为 NULL 而不是依靠调用程序。

注意:原始的编块版本不支持取消操作。对编块 C/C++ 环境中中断的正确支持涉及其它变量及在每一直接或间接编块的调用后对它们的明确测试、中断系统级等待操作(如 connect())的 OS 特定方法以及跟踪需要中断的操作的其它“基础结构”(如 connect() 调用被埋藏在几级函数调用之下。)

Look4sat蓝牙追星云台 //这是一个追星云台的小程序 //配合Look4sat蓝牙传输数据(W*** A***),并让电机做出动作 //app设置内填好ESP32的蓝牙MAC,数据格式:W$AZ A$EL //希望大家可以共同改进 阅读详情

相关推荐

llama.cpp量化模型在MTT显卡上的性能对比:S80/S3000/S4000实测数据

本文基于摩尔线程MTT S80、S3000S4000三款显卡,对llama.cpp量化模型进行了深度性能实测。报告详细对比了不同量化精度(如Q4_K_M、Q6_K)在Llama 3.2 1BQwen 2.5 7B模型上的推理速度、显存占用、功耗及温度表现,为开发者根据硬件选择最优模型配置与参数调优提供了关键数据参考实战指南。

week9的博客 303

BREW SDK 九大功能之网络服务

BREW通过ISocketINetMgr可以实现主要的网络功能。从网络整体来看,Socket是不同主机上应用程序之间的一个虚拟的接口,具有跨平台特性。从程序员角度来看,Socket是应用程序网络设备的一个接口,特殊的I/O。socket有3种类型:面向连接的字节流套接口(Stream Sockets),无连接的数据报套接口(Datagram Sockets)只对Internet协议有效,用于

我相信...... 1640

6.4 实战项目:基于Agent内核构建Code Review智能体

本文介绍了一个基于Agent内核构建的智能Code Review系统实战项目。系统采用多Agent协作架构,包含代码质量分析、安全漏洞识别、性能优化建议等核心功能模块。文章详细展示了系统架构设计,采用协调器Agent管理多个专业Agent协同工作,并提供了基础Agent框架协调器Agent的TypeScript实现代码。项目结合了AI Agent核心原理多Agent协作机制,实现了自动化的代码审查流程,能够生成详细的审查报告,帮助开发者提升代码质量安全性。

yonggeit的博客 2844

BREW进阶与精通——3G移动增值业务的运营、定制与开发》连载之50---BREW SDK 九大功能之网络服务

BREW通过ISocketINetMgr可以实现主要的网络功能。从网络整体来看,Socket是不同主机上应用程序之间的一个虚拟的接口,具有跨平台特性。从程序员角度来看,Socket是应用程序网络设备的一个接口,特殊的I/O。socket有3种类型:面向连接的字节流套接口(Stream Sockets),无连接的数据报套接口(Datagram Sockets)只对Internet协议有效,用于

我相信...... 2518

CDMA增值业务平台BREW的研究与应用(1)

CDMA增值业务平台BREW的研究与应用(1)2003年9月11日  作者:  移动锋行  BREW概述 BREW(Binary Runtime Environment for Wireless,无线二进制运行环境),是高通公司推出CDMA网络 "无线互联网发射平台" 上增值业务开发运行的基本平台。

mobilechannel的专栏 1786

mac brew安装遇到的找不到: command not found

1,举例说明mtr命令安装brew install mtr2,运行mtr报错$ mtr -bash: mtr: command not found3,原因是安装过程中位置不对,需要手动做软连接ln -s /usr/local/Cellar/mtr/0.86/sbin/mtr /usr/local/bin/mtr4,运行mtr,还是报错$ mtr mtr: unable to get raw sock

guoer9973的专栏 1万+

BREW进阶与精通——3G移动增值业务的运营、定制与开发》连载之50---BREW SDK 九大功能之网络服务...

BREW通过ISocketINetMgr可以实现主要的网络功能。从网络整体来看,Socket是不同主机上应用程序之间的一个虚拟的接口,具有跨平台特性。从程序员角度来看,Socket是应用程序网络设备的一个接口,特殊的I/O。socket有3种类型:面向连接的字节流套接口(Stream Sockets),无连接的数据报套接口(Datagram Sockets)只...

weixin_34265814的博客 312

Brew FAQ-常见问答(2)

(1)使用 ITAPI_MakeVoiceCall 进行语音呼叫后,为什么在我对“Return to Application(返回应用程序)”提示响应“No(否)”时我的应用程序似乎要重新启 动? 请确保参数 clsReturn(调用结束后要启动的应用程序) 在 ITAPI_MakeVoiceCall 的调用中为 0(零)。如果您将 clsReturn 指定为您的应用程序的 ClassID, ...

mxdxm8899的专栏 381

BREW SDK 版本的区别:2 万字深度详解

本文系统梳理了高通BREW SDK从1.x到BREWMP版本的演进历程与技术差异。1.x版本(2001-2003)奠定基础架构,支持基础应用开发;2.x版本(2003-2006)实现功能爆发,新增多媒体、网络现代UI框架;3.x版本(2007-2009)面向智能化转型,重构多媒体框架并引入触摸屏支持;BREWMP(2010后)转向操作系统化,提供完整应用框架开发工具。文章详细对比了各版本在架构模型、API特性、开发工具等方面的差异,分析了迁移策略兼容性方案,并指出BREW技术对移动开发生态的历史贡献。

油墨香^-^的博客 549

CDMA增值业务平台BREW的研究与应用

<!--google_ad_client = "pub-2947489232296736";/* 728x15, 创建于 08-4-23MSDN */google_ad_slot = "3624277373";google_ad_width = 728;google_ad_height = 15;//--><script type="text/javascript"

zgqtxwd的专栏 601

BREW SDK 九大功能之系统服务

本文从 BREW SDK 九大功能中的系统服务入手,详细介绍了 ISHELL、IDisplay、IGraphics、IFileMgr、INetMgr、IMedia、ITimer、ITask 等核心接口的用法、原理最佳实践。通过大量的代码示例实战经验,我们剖析了系统服务在构建 BREW 应用中的关键作用。系统服务是 BREW 应用开发的基石,它提供了应用运行所需的所有底层能力。掌握系统服务,意味着掌握了控制设备、优化性能、构建稳定应用的能力。

油墨香^-^的博客 130

忆龙2009:Brew FAQ-常见问答(2)

(1)使用 ITAPI_MakeVoiceCall 进行语音呼叫后,为什么在我对“Return to Application(返回应用程序)”提示响应“No(否)”时我的应用程序似乎要重新启 动? 请确保参数 clsReturn(调用结束后要启动的应用程序) 在 ITAPI_MakeVoiceCall 的调用中为 0(零)。如果您将 clsReturn 指定为您的应用程序的 ClassID,

忆龙2009 2189

BREW精要之事件驱动模型

BREW应用程序的模型是基于一个事件驱动的协作式多任务模型。事件处理机制的核心问题是程序应该只处理需要的事件,对于不需要处理的事件,需要返回给系统处理。应用在加载之后可以通过HandleEvent()函数接收所有输入的事件,然后会通过返回TRUE(已处理)或FALSE(未处理)指示是否处理事件。AEE层存在一个全局的事件队列,所有的事件都存储在该队列中,如果队列中的事件在分...

weixin_34026276的博客 111

BREW进阶与精通——3G移动增值业务的运营、定制与开发》连载之14---BREW精要之事件驱动模型

        BREW应用程序的模型是基于一个事件驱动的协作式多任务模型。事件处理机制的核心问题是程序应该只处理需要的事件,对于不需要处理的事件,需要返回给系统处理。应用在加载之后可以通过HandleEvent()函数接收所有输入的事件,然后会通过返回TRUE(已处理)或FALSE(未处理)指示是否处理事件。AEE层存在一个全局的事件队列,所有的事件都存储在该队列中,如果队列中的事件在分

我相信...... 2044

BREW进阶与精通——3G移动增值业务的运营、定制与开发》连载之14---BREW精要之事件驱动模型...

BREW应用程序的模型是基于一个事件驱动的协作式多任务模型。事件处理机制的核心问题是程序应该只处理需要的事件,对于不需要处理的事件,需要返回给系统处理。应用在加载之后可以通过 HandleEvent()函数接收所有输入的事件,然后会通过返回TRUE(已处理)或FALSE(未处理)指示是否处理事件。AEE层存在一个全局的事件队列,所有的事件都存储在该队列中,如果队列中的事件在分发后处理完毕或...

编程开发资料库 141

BREW™ SDK入门篇(一)

第一部分 -  预备知识在跟随本文学习相关知识点之前,你需要以下环境:Microsoft Visual C++ 6.0®(或更高版本)1.1版的BREW SDK(或更高版本).要了解系统最低要求,获得更细节的资料,SDK的安装指导,请查看SDK 1.1的README文件。注意,在这里我假设你已经读过了本系列中之前的一篇文章,“什么是BREW”。在以下的例子中,你需要知道,文件名是非常重要的。确切

mobilechannel的专栏 2695

KEPServerEX 6 根证书补丁.zip

安装kepserver6即便联网安装时,有时也会提示check root certificates,先运行这个,这个运行之后没有弹出框之类的。然后在安装kep

插件框架C++20110920

一个C++插件框架,对插件内核添加了一些注释,添加了一个测试插件,用于说明插件消息的处理方式。

上一篇: BREW是什么?
下一篇: 构建可移植 BREW™ 应用程序的方法
mobilechannel
博客等级 码龄22年 36粉丝 431原创
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值