用socket的实现http请求的方法.doc_第1页
用socket的实现http请求的方法.doc_第2页
用socket的实现http请求的方法.doc_第3页
用socket的实现http请求的方法.doc_第4页
用socket的实现http请求的方法.doc_第5页
免费预览已结束,剩余12页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

公司做了一个小型的wap浏览器的项目,其中涉及到用socket的实现http请求的方法,由于网上相关资料比较少,尤其是详细的资料比较少,所以走了不少弯路。在此仅从实现的角度说明MTK平台用Socket实现HTTP的方法,希望能给后来者一些微小的帮助。一、MTK平台Socket联网过程熟悉PC机编程的人都知道,Socket编程接口分两套:TCP和UDP;TCP和UDP中又有服务器端和客户端的概念,这里讲的是TCP的客户端编程接口。MTK平台中Socket创建步骤: 1、soc_create() 创建Socket; 2、soc_setsockopt 设置Socket为非阻塞模式; 3、soc_setsockopt 设置Socket选项为连接,读,写,关闭;不清楚为什么要连续设置两次,如有高人路过,请指点; 4、如果是CMNET联网并且请求中用到了英文域名还需要解析域名soc_gethostbyname,除非使用ip作为域名,解析出来的IP作为我们建立连接的目标IP;如果是CMWAP联网,直接跳到第5步,直接连接移动或联通的网关:72:80; 5、soc_connect与服务器建立连接; 6、soc_send 发送请求; 7、soc_recv 接收服务器返回的数据; 8、soc_close 关闭Socket; 9、如果需要关闭数据账户soc_close_nwk_account二、CMNET,CMWAP方式下的HTTP请求内容格式HTTP请求格式:GET方法MTK模拟器中wap浏览器发送的请求内容“GET /go_13596557 HTTP/1.1Host: User-Agent: SQH_D480B_01/LB19504/WAP2.0 ProfileAccept: application/vnd.wap.wmlc, * /(想当长,省去后面部分)Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, GB2312, windows-1252, us-asciiAccept-Language: zh-tw, zh-cn, enCookie: JSESSIONID=aAQP0FIXp3z7Connection: Keep-Alive“POST方法对一些需要向服务器传入参数的请求,按名称搜索等请求。还以空中网天气查询为例,之中的其他城市天气查询,输入其他城市名称或电话区号查询:“POST /weather/search.jsp?setcity=1 HTTP/1.1Host: User-Agent: SQH_D480B_01/LB19504/WAP2.0 ProfileAccept: application/vnd.wap.wmlc, */* /(想当长,省去后面部分)Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, GB2312, windows-1252, us-asciiAccept-Language: zh-tw, zh-cn, enContent-Type: application/x-www-form-urlencoded; charset=utf-8Cookie: KONG_ACCESS=AWYZhg=; JSESSIONID=a91MDc6qoMYfConnection: Keep-AliveContent-Length: 46/get方法没有这一项/传给服务器46字节长的数据(参数)“当然如果是CMWAP联网方式也要和上述的GET方法一样设置Host和X-Online-Host项,Host:72X-Online-Host: 以上的内容,可以在调试状态下运行模拟器的wap浏览器,在soc_send方法处插入断点观察。HTTP的其他方法,由于在应用中没有用到,在这里不做介绍。三、CMNET,CMWAP连接差别1、GPRS账户:与pc机上的socket客户端接口不同,手机客户端在soc_create,soc_gethostbyname接口中都多了参数 nwt_acount_id,只的是一般在“网络服务”-“数据账户”-“GPRS”下的GPRS数据账户id,一般起始的一个账户id 是10,往下递增1,在建立连接过程中,如果是CMWAP方式联网,soc_create,soc_gethostbyname接口就要设置接入点为 CMWAP的账户id,CMNET就要设置接入点为CMNET的账户。2、目标服务器:还以空中网的天气服务为例,CMNET情况下,soc_connect需要连接””这个ip,如果请求的url为”/weather/home.jsp” ,还需要调用soc_gethostbyname接口去解析域名;如果是CMWAP方式联网,soc_connect只需要连接移动或联动的网关”72:80”。3、HTTP请求内容格式(或称报文):如第二节所述。四、SIM1还是SIM2联网 SIM1还是SIM2联网,MTK平台是通过创建socket时传入的nwt_acount_id区分的,如果是SIM1上网,账号就是指的是一般在“网络服务”-“数据账户”-“GPRS”下的对应的GPRS数据账户id;如果是SIM2,通过在四字节的账户id其他字节设置掩码来区分。设置接口比如07B平台的always_ask_encode_data_account_id,6235_08A的cbm_encode_data_account_id接口。不同平台可能略有差别。五、联通卡还是移动卡?参考其他Socket联网代码中有的以接入点是否为”uniwap”来判断是不是联通的代理上网,但是通过实验,即使在联通卡时连接移动的”cmwap” 账户,也是可以正常联网的。不知道设计“GPRS数据账户”的最初意图是什么?通过apn来区分同一内部ip地址网关不同的公网ip吗?如有高人路过,请指点;六、HTTP1.1与Transfer-Encoding 为chunked的编码方式 发送一个请求后,如果服务器返回的消息头内容包括“Transfer-Encoding: chunked”那么他的传输编码为“chunked”类型。这种传输类型的数据体内容格式是这样:16进制数字字符串 1到4个字节 lenrnlen 长的数据体rn16进制数字字符串 1到4个字节 lenrnlen 长的数据体rn16进制数字字符串 1到4个字节 len = 0rnrn其中,长度len是16进制的数字,表示本段数据体的长度(字节数),回车换行后,就是这一段数据真实内容,这就是一段数据体的格式,一段接一段;直到数据体长度为0的数据段出现,紧接着两个回车换行,标识本次请求的数据均已接收完毕。不过socket可以根据soc_recv返回值等于0来判断接收数据结束。如果收到的是这个编码类型的内容,需要对接收到的数据进行处理。七、MTK平台的S8类型的误导 MTK平台定义的两个数据类型U8和S8,一看名称我们可能会以为是unsigned char和signed char,但事实并非如此,typedef char S8;typedef unsigned char U8; MTK平台的char默认也是unsigned char类型的,soc_gethostbyname返回值类型是kal_int8(typedef signed char kal_int8;),如果S8或平台的char类型是有符号的字符型,那么,kal_int8和S8应该是等价的,但用S8类型变量作为 soc_gethostbyname的返回值时,经常返回254导致域名不会被正常解析,其实应该返回SOC_WOULDBLOCK(-2),应该是阻塞码,将soc_gethostbyname返回值类型改为kal_int8后,就能正常处理域名解析了。这证明平台的S8类型及char类型默认是无符号的。八、不理解的链接错误? 在添加连接超时功能时用到了gui_start_timer和gui_cancel_timer时,没有加入#include gui.h时,出现以下链接错误:Error: L6286E: Value(0x818153e) out of range(-0x400000 - 0x3fffff) for relocation #13 (wrt symbol gui_cancel_timer) in Socket.obj(i. SocDinit)加上#include gui.h时,就没有这个问题,如果程序找不到这个符号,应该是个编译错误,在此为什么是个链接错误。.cmwap的http协议模拟cmwap必须通过72:80端口进行代理走http协议.一般是1.1#defineProxyHttpRequestHeaderPOST/HTTP/1.1rnX-Online-Host::12345rnKeep-Alive:closernContent-Length:%drnrn/X-Online-Host后面跟着的就是目标机器网络地址和端口/Content-Length后面填写随后的数据长度/头部后面跟着就是随后数据,最好使用base64编码./服务器端收到数据一般经过移动网关修改.8.cmwap的http模拟:服务器端返回格式:#defineHTTP_RESPONSE_HEADERHTTP/1.1200OKrnContent-Length:%drnrn/Content-Length后面填写随后的数据长度/头部后面跟着就是随后数据,最好使用base64编码.具体问题可以与我讨论:QQ1522885直接用socket实现HTTP协议2010-02-15 17:07从HTTP服务器上下载一个文件有很多方法, “热心”的微软提供了 WinInet 类,用起来也很方便。当然,我们也可以自己实现这些功能,通过格式化请求头很容易就能实现断点续传和检查更新等等功能 。本文附带的工程中有一个支持 HTTP1.1 协议,直接用 Socket 实现下载功能的 DLL,实现了以下功能: 1. 连接主机 2. 格式化请求头 3. 设置接收,发送超时 4. 接收并分析回应头 连接,发送,设置超时,接收数据等我就不细说了,windows socket早就做好了,调用相应的函数就OK了。要想从服务器下载文件,首先要向服务器发送一个请求。HTTP 请求头由若干行字符串组成。下面结合实例说说 HTTP 请求头的格式。假设要下载 /index.html 这个网页 ,那么请求头的写法如下:第1行:方法,请求的内容,HTTP协议的版本下载一般可以用GET方法,请求的内容是“/index.html”,HTTP协议的版本是指浏览器支持的版本,对于下载软件来说无所谓,所以用1.1版 “HTTP/1.1”;“GET /index.html HTTP/1.1”第2行:主机名,格式为“Host:主机”在这个例子中是:“Host:”第3行:接受的数据类型,下载软件当然要接收所有的数据类型,所以:“Accept:*/*”第4行:指定浏览器的类型有些服务器会根据客户服务器种类的不同会增加或减少一些内容,在这个例子中可以这样写:“User-Agent:Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)”第5行:连接设置设定为一直保持连接:“Connection:Keep-Alive”第6行:若要实现断点续传则要指定从什么位置起接收数据,格式如下:“Range: bytes=起始位置 - 终止位置”比如要读前500个字节可以这样写:“Range: bytes=0 - 499”;从第 1000 个字节起开始下载:“Range: bytes=999 -”最后,别忘了加上一行空行,表示请求头结束。整个请求头如下:GET /index.html HTTP/1.1Host:Accept:*/*User-Agent:Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)Connection:Keep-AliveCHttpSocket 提供了 FormatRequestHeader()函数,用以格式化输出HTTP请求头。代码如下:/根据请求的相对URL输出HTTP请求头const char *CHttpSocket:FormatRequestHeader(char *pServer,char *pObject, long &Length, char *pCookie,char *pReferer,long nFrom, long nTo,int nServerType) char szPort10; char szTemp20; sprintf(szPort,%d,m_port); memset(m_requestheader,0,1024); /第1行:方法,请求的路径,版本 strcat(m_requestheader,GET ); strcat(m_requestheader,pObject); strcat(m_requestheader, HTTP/1.1); strcat(m_requestheader,rn); /第2行:主机 strcat(m_requestheader,Host:); strcat(m_requestheader,pServer); strcat(m_requestheader,rn); /第3行: if(pReferer != NULL) strcat(m_requestheader,Referer:); strcat(m_requestheader,pReferer); strcat(m_requestheader,rn); /第4行:接收的数据类型 strcat(m_requestheader,Accept:*/*); strcat(m_requestheader,rn); /第5行:浏览器类型 strcat(m_requestheader,User-Agent:Mozilla/4.0 (compatible; MSIE 5.00; Windows 98); strcat(m_requestheader,rn); /第6行:连接设置,保持 strcat(m_requestheader,Connection:Keep-Alive); strcat(m_requestheader,rn); /第7行:Cookie. if(pCookie != NULL) strcat(m_requestheader,Set Cookie:0); strcat(m_requestheader,pCookie); strcat(m_requestheader,rn); /第8行:请求的数据起始字节位置(断点续传的关键) if(nFrom 0) strcat(m_requestheader,Range: bytes=); _ltoa(nFrom,szTemp,10); strcat(m_requestheader,szTemp); strcat(m_requestheader,-); if(nTo nFrom) _ltoa(nTo,szTemp,10); strcat(m_requestheader,szTemp); strcat(m_requestheader,rn); /最后一行:空行 strcat(m_requestheader,rn); /返回结果 Length=strlen(m_requestheader); return m_requestheader;请求头发送给服务器后就可以接收来自服务器的回应头了。回应头也是由若干行字符串组成,除了第一行和最后一个空行以外,每一行都由一个域和一个值组成。第一行包括了服务器的回应状态 ,从 2XX 到 5XX,每个状态码都有不同的意思,详细内容可以查看RFC文档下载需要关心的有 :2XX表示成功,可以继续读取数据;3XX表示目标已经转移,新的地址在“Location”域中;4XX表示客户端错,可能是下载地址不对,等等;5XX表示服务器端错 。回应头中的域有“Content-Length”,“Accept-Ranges”,“Content-Type”,“Date”,“Last-Modified”,“Location”等等内容 ,下载比较关心的域有“Content-Length”域和“Location”域。“Content-Length”表示下载文件的大小 ,“Location”表示目标的实际存放位置,当回应码为3XX时就要用该域中的值重新连接。附带源码中的 CHttpSocket 类提供了以下几个方法,分别用来读取服务器状态码,某个域的值,回应头中的一行以及整个回应头: int GetServerState(); /返回服务器状态码 -1表示不成功int GetField(const char* szSession,char *szValue,int nMaxLength);/返回某个域值,-1表示不成功int GetResponseLine(char *pLine,int nMaxLength);/获取返回头的一行 const char* GetResponseHeader(int &Length);取得回应头后,如果回应码为2XX并且“Content-Length”的值不等于0就表示可以接收下载文件数据了,接下来的工作就很简单了,调用 CHttpSocket:Recevie()直到接收的数据长度等于“Content-Length”的值就可以了 。一个完整的使用过程由以下几个步骤组成: 1. 调用AfxParseURL()分析URL得到Server和下载路径; 2. 调用CHttpSocket:Socket()创建套接字; 3. 调用CHttpSocket:Connect()连接服务器; 4. 调用CHttpSocket:FormatRequestHeader()格式化请求头; 5. 调用CHttpSocket:SendRequest()向服务器发送请求头; 6. 调用CHttpSocket:GetServerState()得到回应状态码; 7. 调用CHttpSocket:GetField(Content-Length)得到下载文件的大小; 8. 调用CHttpSocket:Receive()接收数据直到数据接收完成; 本文附带源代码还包括了一个使用 CHttpSocket 实现下载功能的例子工程。注意,所有的调用都是阻塞的,所以最好为一个下载任务创建一个线程 ,否则会导致界面无法响应用户输入。程序运行界面如下图所示:该图显示了请求头,回应头以及下载进度。 当然,要真正实现多任务多线程下载还有很多工作要做。本文仅仅讨论了自己实现下载的一种可能性,希望对读者有所帮助HTTP协议是基于请求响应范式的。HTTP的请求格式:统一资源标识符、协议版本号,后边是MIME信息包括请求修饰符、客户机信息和可能的内容。-请求方法URLHTTP协议的版本号提交的元信息*空行*实体-HTTP的响应格式:一个状态行包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。-HTTP协议的版本号应答状态码应答状态码说明接收的元信息*空行*实体-下面介绍一下HTTP协议的内部操作过程。首先,简单介绍基于HTTP协议的客户/服务器模式的信息交换过程,如下图所示,它分四个过程,建立连接、发送请求信息、发送响应信息、关闭连接。/图略:csdn不支持图片上传,2.6下面,讨论HTTP协议下客户/服务器模式中信息交换的实现。1.建立连接连接的建立是通过申请套接字(Socket)实现的。客户打开一个套接字并把它约束在一个端口上,如果成功,就相当于建立了一个虚拟文件。以后就可以在该虚拟文件上写数据并通过网络向外传送。2.发送请求打开一个连接后,客户机把请求消息送到服务器的停留端口上,完成提出请求动作。HTTP/1.0请求消息的格式为:请求消息=请求行(通用信息|请求头|实体头)CRLF实体内容请求行=方法请求URLHTTP版本号CRLF方法=GET|HEAD|POST|扩展方法URL=协议名称+宿主名+目录与文件名请求行中的方法描述指定资源中应该执行的动作,常用的方法有GET、HEAD和POST。不同的请求对象对应GET的结果是不同的,对应关系如下:对象GET的结果文件文件的内容程序该程序的执行结果数据库查询查询结果HEAD要求服务器查找某对象的元信息,而不是对象本身。POST从客户机向服务器传送数据,在要求服务器和CGI做进一步处理时会用到POST方法。POST主要用于发送HTML文本中FORM的内容,让CGI程序处理。GET根据URL,会请求文件、数据库查询结果、程序运行结果等多种内容。头信息又称为元信息,即信息的信息,利用元信息可以实现有条件的请求或应答。常用的头信息包括:Accept:浏览器可接受的MIME类型。Accept Charset:浏览器可接受的字符集。Accept Encoding:浏览器能够进行解码的数据编码方式,比如gzip。Accept Language:浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到。Authorization:授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中。Connection:表示是否需要持久连接。如果Servlet看到这里的值为“Keep Alive”,或者看到请求使用的是HTTP1.1(HTTP1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点,Servlet需要在应答中发送一个Content Length头,最简单的实现方法是:先把内容写入ByteArrayOutputStream,然后在正式写出内容之前计算它的大小。Content Length:表示请求消息正文的长度。Cookie:这是最重要的请求头信息之一,参见后面Cookie处理一章中的讨论。From:请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用到它。Host:初始URL中的主机和端口。请求头告诉服务器怎样解释本次请求,主要包括用户可以接受的数据类型、压缩方法和语言等。实体头实体信息类型、长度、压缩方法、最后一次修改时间、数据有效期等。实体请求或应答对象本身。一个请求的例子为:GET/zju/index.htmHTTP/1.03.发送响应服务器在处理完客户的请求之后,要向客户机发送响应消息。HTTP/1.0的响应消息格式如下:响应消息=状态行(通用信息头|响应头|实体头)CRLF实体内容状态行=HTTP版本号状态码原因叙述状态码表示响应类型1保留2表示请求成功地接收3为完成请求客户需进一步细化请求4客户错误5服务器错误响应头的信息包括:服务程序名,通知客户请求的URL需要认证,请求的资源何时能使用。下面是一些常用的响应头:Date:Mon,08Sep200317:10:49GMTServer:Apache/1.3.23Last-Modified:Mon,08Sep200303:48:19GMTETag:32417-c4-3e5d8a83Accept-Ranges:bytesContent-Length:196Connection:closeContent-Type:text/html一个响应的例子为:HTTP/1.02004.关闭连接客户和服务器双方都可以通过关闭套接字来结束TCP/IP对话示例:下面用最常用的GET方法,来说明具体的报文应用-GETHTTP/1.0accept:www/source;text/html;image/gif;image/jpeg;*/*User_Agent:myAgent*空行*-这个报文是向主机请求一个缺省HTML文档。客户端HTTP协议版本号是1.0版,元信息包括可接收的文件格式,用户代理,每一段之间用回车换行符分隔,最后以一个空行结束。发向服务器后,如果执行过程正常,服务器返回以下代码:-HTTP/1.1200OKDate:Tue,14Sep199902:19:57GMTServer:Apache/1.2.6Connection:closeContent-Type:text/html*空行*.-HTTP/1.1表示这个HTTP服务器是1.1版,200是服务器对客户请求的应答状态码,OK是对应答状态码的解释,之后是这个文档的元信息和文档正文。(相关应答状态码和元信息的解释请参阅Inetrnet标准草案:RFC2616)。参考资料:GPIO设置篇一、GPIO有关的函数1GPIO_ModeSetup:函数原型:void GPIO_ModeSetup(kal_uint16 pin, kal_uint16 conf_dada)功能:设置GPIO的工作模式是作为GPIO,还是作为专有功能接口。参数:pin:GPIO 的pin脚号,对应于原理图上MTK62XX 主CPU芯片的上的GPIO标号conf_dada:值有03。其中0是表示作为GPIO模式,其他根据专有功能的不同进行设置。2GPO_InitIO函数原型:void GPIO_InitIO(char direction, char port)功能:初始化GPIO的工作方向是作为输入,还是作为输出参数: direction:工作方向,0表示输入,1表示输出 port:GPIO的pin脚3GPIO_ReadIO函数原型:char GPIO_ReadIO(char port)功能:从GPIO读取数据参数: port:GPIO的pin脚4GPIO_WriteIO函数原型:void GPIO_WriteIO(kal_char data, kal_char port)功能:往GPIO写数据参数:data: 1表示给高电平,0表示给低电平 port:GPIO的pin脚备注:这些函数在Gpio.C中可以找到。二、GPIO模式设置 GPIO口在系统上电的时候,有的是默认高电平,有的是默认低电平,这是MCU内部决定的,软件无法更改,但是在系统开机过程中,会对GPIO进行初始化,MCU中有几个GPIO模式初始化寄存器,通过这个寄存器给GPIO设置初始模式。 例如:以下这个寄存器就是用来设置0-7号GPIO的模工作模式的。 这个初始化过程在Gpio_Drv.C中的函数GPIO_init()中,项目开始的时候,先要检查这个部分的模式设置是否正确。三、各个功能模块的GPIO设置1. LCD背光,马达有的LCD背光是靠GPIO进行控制的,有的则靠PMIC进行控制。但不管那个方式进行控制,都只需修改Custom_equipment.c中的相关部分就可以了,具体如下:首先,检查数组GPIO_MAP_ENTRY gpio_map_tbl = GPIO_VAILD, GPIO_PORT_24, netnameGPIO_LABEL_LCD_BACKLIGHT, NULL ,;将没有使用的GPIO,用GPIO_INVALID给屏蔽掉。然后,修改函数custom_cfg_gpio_set_level,在对应的GPIO类型上将控制函数添加进去即可。比如: switch(gpio_dev_type) case GPIO_DEV_LED_MAINLCD: if( gpio_dev_level = LED_LIGHT_LEVEL0)/ LEVEL0- LEVEL5是背光由若到强的控制,LEVEL0表示关闭背光GPIO_WriteIO(GPIO_OFF, custom_cfg_outward_gpio_port(GPIO_LABEL_LCD_BACKLIGHT) ); else GPIO_WriteIO(GPIO_ON, custom_cfg_outward_gpio_port(GPIO_LABEL_LCD_BACKLIGHT) ); PWM2_level(gpio_dev_level); break;2. 蓝牙在文件bt_hw_define.h中参照原理图进行对应GPIO的修改。 #define BT_GPIO_RESET 52/39 /GPIO_39 : PMIC reset #define BT_GPIO_DSC 36/;4 /GPIO_4 : to disconnect RFComm lin

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论