zoukankan      html  css  js  c++  java
  • (转载) mtk 10A 建立socket连接问题

    //============================================================================

    1.srv_dtcnt_get_acc_id_by_apn()获取apn对应的accont_id号

    2.cbm_register_app_id_with_app_info()注册一个app_id

    3.cbm_set_app_id()将刚才获取的account_id进行编码

    4.最后cbm_deregister_app_id()注销app_id。此步骤必不可少,可能造成死机

     //============================================================================

    10A:

    1.建立相关的数据账号
          在MTK中,要想建立相关的socket连接进行收发数据操作,在这之前必须建立相应的数据账号。在MODIS中,你可以不配置什么数据账号,直接调用soc_create()时最后一个参数填0,就可以进行相应的socket操作。但是放到手机真机上,这就不行了,数据账号乱来,你可以过了soc_create(),soc_setsockopt(),但是后续的soc_gethostbyname()或者soc_connect()就会出现返回值-2,然后一直等不到相对应的notify函数。
          在10A之前的MTK版本,数据账号可以直接10后者14然后调用cbm_encode_data_account_id(),就可以得到了分别对应的是cmwap和cmnet,在10A之后的版本,数据账号data_account有较大的改动,我现在调用的是以下的2个接口函数,实现的cmwap和cmnet。
          cbm_register_app_id_with_app_info()、cbm_set_app_id().
          kal_uint8 app_id = 0;
          kal_uint32 acct_id = 0;
          cbm_app_info_struct info;
          info.app_str_id = EM_SOCKET_TEXT;
          info.app_icon_id = EM_SOCKET_ICON;
          info.app_type = 0;
          cbm_register_app_id_with_app_info(&info, &app_id);  
          acct_id = cbm_set_app_id(CBM_DEFAULT_ACCT_ID, app_id);
           上面是cmwap、uniwap的数据账号注册方式,其中app_type是0或者DTCNT_APPTYPE_NONE,而set_app_id时需要填写CBM_DEFAULT_ACCT_ID。
           cmnet、uninet的数据账号注册方式,就是将app_type改成DTCNT_APPTYPE_EMAIL就可以了,因为EMAIL默认用cmnet进行联网

    2.socket的相关函数
           这方面网上文档有很多,只要网上找一下,看看就能明白了。具体代码例子可以借鉴MTK工程模式上自带的一个SOCKET_test的一个小demo。
           我这就粗略的讲讲这几个函数。
           soc_create()通过我上述讲的得到相应的数据账号acct_id,添进去把相关参数填完整就可以了,一般返回值不是负的就可以了。
           soc_setsockopt()这个函数需要调用2次,一次设置成SOC_NBIO非阻塞的,再一次设置成SOC_ASYNC异步的,一般也没什么问题。
           soc_gethostbyname()这个函数,只有在cmnet的情况下(即不经过移动、联通的默认代理网关)需要用到,当然如果你知道你所要连接的服务器IP地址,那也就无所谓调不调这个函数了,这个函数一般情况下返回值为-2,需要你自己写个相对应的notify函数。
           soc_connect()函数,就是将你要试图连接的服务器IP,端口号填进去就可以了,如果你是用cmwap/uniwap的话,就是连他们的代理网关10.0.0.172,端口号80,这个函数通常也是不会直接就返回成功的,它会返回个-2,然后异步的去等它对应的notify函数(特别提示:这个地方有时网络不好,很容易返回-2后,得不到后续的notify,所以加个定时器比较好点),没用过这个函数的可能会问,连接了代理网关,发出去的请求怎么知道请求的是哪个服务器呢?我开始也很疑惑,其实这个时候,连接指定服务器的,就是我们发送出去的HTTP头中带的那个HOST
           soc_send()函数,将你组装的HTTP头及数据包,填进去就OK了,它会返回你发送出去的数据包的长度,以此表示成功与否,当然相应的防错处理还是要加进去的,还有就是这个函数调用后,会直接调用后面的soc_recv(),中间可能服务器还没响应过来,你直接调soc_recv()可能会失败,保险期间,加个定时器,不用太久100毫秒就可以了。能提高后面soc_recv()很大的成功率。
           soc_recv()函数,这个函数就是你真正接收数据的地方,它在手机端很容易返回回来0,说明什么也没得到,很正常,继续调这个函数收数据就可以了。 一般它收到多少字节,就返回这个字节数。这个函数中间涉及比较多的东西,这就不多说了,后面再说。
           soc_close()函数,就是把相关的socket的ID关了,这个网络连接OVER了,如果想对同一服务器再次发送请求的话,可以不close,因为重新create socket ID会有点慢,跟电脑上断网,重连一个道理。

    3.发送数据包的HTTP头
    POST /weather/index.action HTTP/1.1
    Host:xx.xx.xx.xx:8080
    Connection:Keep-Alive
    Range: bytes=0-2048
    Content-Type:application/x-www-form-urlencoded
    Content-Length:15
    qu=澶у叴瀹夊箔

    这是我们这一个请求天气的请求,POST、GET两种方式根据你指定服务器端的请求方式有关,自己决定
    /weather/index.action,相关的action请求;HTTP/1.1 HTTP协议1.1
    Host:xx.xx.xx.xx:8080,请求的服务器,连接时,都需要把hostname,改成对应的IP
    Connection:Keep-Alive,连接类型长连接
    Content-Type:application/x-www-form-urlencoded,内容类型,这个我还没搞透不是很明白
    Range: bytes=0-2048,range的传输方式,表示请求的内容从0-2048字节传输给你,如果改成Range: bytes=2048-,就表示请求的内从2048字节开始传输给你,没有的话,就传空的给你,range是一种支持断点续传的格式,很不错,不过可能需要服务器端,设置相应的range参数才行
    Content-Length:,就是你发送出去的内容的长度,“qu=澶у叴瀹夊箔”发送出去的内容
    发送出去的HTTP请求,大致就是这样,至于上传什么的,还没做。呵呵,就不写出来误导了。

    4.soc_recv(),我刚刚前面说过,这个函数的话,中间处理可能都会放在这,所以比较复杂。
    收到的数据包
    HTTP/1.1 200 OK
    Content-Length: 22957
    Date: Wed, 20 Apr 2011 01:59:39 GMT
    Content-Disposition: inline
    Content-Type: application/octet-stream
    Server: Apache-Coyote/1.1

           200表示请求成功,其他的还有206、400、404、500等等状态码,具体的,网上找吧,这里不多说了。
           说说Content-Length,这是一种HTTP的传输格式
           我总结了下,我用cmwap、uniwap请求时,返回的就是Content-Length,而我用cmnet、uninet请求时,返回的就是Chunked格式。这2种格式需要你去做相应的处理。Content-Length就是直接把整个请求的内容的长度回给你了,你去调soc_recv(),收齐就可以了,但这个Content-Length有个弊端,它有限制,超过一定字节后,Content-Length就传不过来了,会直接返回Connection:close,Content-Length这种情况的解析这里就不详细说了。
           重点说说Chunked,这个格式,我觉得比较好,它可以传一个很大很大的东西,因为它再传之前,就已经做了切割处理,把所要传输过来的东西,打散成一个一个小的。这一个一个小的,最大的就 十六进制2000,即8192个字节。它的格式是返回的HTTP头,后面就会带一个十六进制的数,你自己转化成十进制,就会发现这就是内容的大小,它传输完会以一个0为结尾,下面是一个例子
    HTTP/1.1 200 OK
    Server: Apache-Coyote/1.1
    Content-Disposition: inline
    Content-Type: application/octet-stream
    Transfer-Encoding: chunked
    Date: Mon, 16 May 2011 10:29:16 GMT
    135
    day,dc,dd,dl,dt,nc,nd,nl,nt
    0,晴,无持续风向,≤3级,26℃,多云,无持续风向,≤3级,13℃
    1,多云,北风,3-4级,25℃,晴,北风,4-5级,14℃
    2,晴,北风,4-5级,24℃,晴,无持续风向,≤3级,13℃
    3,晴,无持续风向,≤3级,27℃,晴,无持续风向,≤3级,13℃
    4,晴,无持续风向,≤3级,24℃,,,,
    2011,05,10,08,05,00,,,,
    2011,05,16,18,29,16,,,,

    0
    其中135,就是十六进制数,即309个字节数,135后有个回车,其次才是真正的内容,最后结束时,会有个0作为结束符,是0之前有回车还是之后我给忘记了。。。;上面的这个例子是传过来内容比较少的,还有的情况就是内容比较多的,(相关的例子手边正好没有,就不放上来了)Chunked会分成几个包,但小包最大不会大于2000,就是十进制8192个字节数,一个小包结束后,不是以0为结尾,而是已下个包的十六进制数为开始,开始传第二个小包,依次下去,到最后了才会以一个0为结束符(当然Chunked传输时,无论是上面数据量多与少,这个结束符0没有都是很正常的)。
    这里我说下我用的Chunked解析方法,展讯上的版本,我领导以前写的,很稳定的解析,我就直接捡了个现成的,移到了MTK上,大致方法就是我收下数据包,然后放到一块缓存buffer中,看看这个Chunked包有没有收完整,没完整就继续收,知道发现一个Chunked包收完整了,就放到相应的文件中去,然后接受下个Chunked包,这里说的Chunked包都是小包(最大8192那种),不是整个请求需要的整个大数据包。可能还有别的更好的解析方法,有知道的朋友可以找我探讨下,(其实我用过网上介绍的主流方法,大概可能是我方法不对,导致效率不高,会出现收到数据,解析时出现定屏情况)


    5.我这个socket模块,以前在展讯上是通过TASK,来进行相关的函数驱动调用的,刚移到MTK时,也是通过TASK,实现我的函数调用的,但是出现了很多意想不到的问题,什么栈溢出,task乱跑,直接开机就死,都出现了;现在的话直接就采取了发送EVENT的方式,来触发我的函数,task虽然很好很强大,但在MTK上,我劝朋友们少用,就连MTK代码上也不太支持我们客户自己定个TASK出来。如有可能还是尽量通过利用MMI_TASK,就是通过EVENT注册、执行的方式,来间接调用MMI_TASK,会减少很多自建task而引发的莫名其妙的死机,当然这也是MTK官方推荐的方案,更符合它平台的特性。

     

    08B/09A:

    1、设置网络账号的接入点:
    在MTK的网络中分wifi、GPRS和GSM三种,我们在上网时使用最多的是GPRS方式。一般情况下,GSM和GPRS分别各有10个账号,在网络->数据账号资料里面可以看到。
    GSM的10个账号资料对应的id是从0-9,GPRS的10个账号资料对应的id是从10-19。每个账号资料里面最关键的是接入点,通常情况下,接入点是CMWAP或CMNET。代表
    是使用cmwap还是cmnet联网方式。这两种联网方式的区别在于,使用cmwap需要经过中国移动的代理服务器10.0.0.172,才能连接到最终的服务器上去。而cmnet则
    直接连接到最终要访问的服务器。账号id在调用soc_create时会用到,由此就决定了用的是哪个接入点,什么方式进行联网。设置接入点可以有两种方式:
    1)选择一个已经设置好接入点的账号id,直接拿来使用。
    2)通过异步的发消息PRT_MMI_PS_SET_GPRS_DATA_ACCOUNT_REQ方式设置你想要用的账号资料的接入点。

    2、生成应用id
    appid = cbm_register_app_id((U16) MAIN_MENU_FUNANDGAMES_TEXT, GetRootTitleIcon(MAIN_MENU_FUNANDGAMES_ICON));

    如果需要,将GPRS状态设置为保持,这样在每次关闭socket描述符后,不会
    关闭GPRS连接,这样在下一次建立TCP连接时,会节省建立GPRS连接的时间,
    否则,每次调用soc_connect的时候会自动去建立GPRS连接,这样会花掉3-6秒。
    cbm_hold_bearer(MOD_MMI, appid);

    3、转换账号id,在MTK联网时,需要用到一个账号id,如果是双卡的手机,
    在调用soc_create之前,账户id需要做转换。
    nwk_account = cbm_encode_data_account_id(nwk_account, sim_id, appid, KAL_FALSE);

    4、创建socket,设置成异步非阻塞的方式,建立TCP连接,设置回调函数,发送和接收数据。

    5、关闭socket

  • 相关阅读:
    点击单元格(LinkToAction)获取Table行号和数据(Table篇一)
    金额和数量不显示0
    自定event事件之全局初始化中自动触发(二)
    自定event事件之手动触发(一)
    Python的requests如何同时post图片二进制流和json数据application/octet-stream
    树莓派点亮LED灯需要几行代码?3行。小孩子都能学会
    50元求解pyqt加载并显示pdf问题
    pyqt5加载pdf文档失败
    建个群,互相关心
    唉,十年前的沙雕照片
  • 原文地址:https://www.cnblogs.com/sierllen/p/2478912.html
Copyright © 2011-2022 走看看