您的位置:首页 > 理论基础 > 计算机网络

CC3200使用官方的Http cli连接服务器

2015-07-28 22:23 806 查看
一、为什么需要HTTP Cli

如果我们要进行HTTP通信,就需要我们合成http协议,获取到服务器的HTTP后,还需要解析,合成是比较简单,但是解析就麻烦了,因为官方合成和解析HTTP协议的代码,所以当然就是直接用楼。

二、什么是Http cli

HTTP是分成服务器和客户端的,cc3200和浏览器就是客户端,web服务器就是我们现在所讲的服务器,我的服务器是tomcat加servlet。HTTP CLi就是专门用于解析和合成HTTP的官方库函数。

三、前序

我是比较倾向于直接用POST完成数据的上传和下载,get是专门用于数据的下载的,主要对我来说还是方便性,所以我就直接讲POST,我曾经用过TCP模拟POST,但是发现CC3200的receive获取服务器的数据,需要2次,这麻烦了,,说不准不同的服务器可能就得receive 3次,甚至更多次,如果自己写代码,那不是麻烦死了,,还得调,,,后面看到官方就有这个例子。sdk最新版可能才有这个例子。在仔细想想,还得解析HTTP的协议,,心都碎了。。

四 HTTP简介

HTTP主要分成头部和主体部分,头部就是包含各种信息,主体部分就是内容。HTTP CLI设计的挺好的,差不多也是根据这两部分来的编写代码。

五 直接上代码,请看注释,代码后面有图有真相

//这是一个任务
void vHttpToServer(void *pvParameters) {

HTTPCli_Struct httpClient;
osi_Sleep(1000);
UART_PRINT("vHttpToServer\r\n");
//连接到服务器,httpClient就是内部需要的一个结构体,
ConnectToHTTPServer(&httpClient);
//发送服务器请求及处理响应
HTTPPostMethod(&httpClient);
LOOP_FOREVER();
}

//http连接操作
static int ConnectToHTTPServer(HTTPCli_Handle httpClient) {
long lRetVal = -1;
struct sockaddr_in addr;

//转化IP
siIp_StrToInt("103.44.145.245", &S_DestinationIP);
/* Set up the input parameters for HTTP Connection */
addr.sin_family = AF_INET;
addr.sin_port = htons(HOST_PORT);
addr.sin_addr.s_addr = sl_Htonl(S_DestinationIP);

/* Testing HTTPCli open call: handle, address params only */
//初始化httpClient
HTTPCli_construct(httpClient);
//连接服务器
lRetVal = HTTPCli_connect(httpClient, (struct sockaddr *) &addr, 0, NULL);
if (lRetVal < 0) {
UART_PRINT("Connection to server failed. error(%d)\n\r", lRetVal);
ASSERT_ON_ERROR(-3);
} else {
UART_PRINT("Connection to server created successfully\r\n");
}

return 0;
}

static int HTTPPostMethod(HTTPCli_Handle httpClient) {
bool moreFlags = 1;
bool lastFlag = 1;
char tmpBuf[4];
long lRetVal = 0;
//设置头部
//头部就是名跟值的对应关系、
//
HTTPCli_Field fields[4] = {
{HTTPCli_FIELD_NAME_HOST, HOST_NAME},
{HTTPCli_FIELD_NAME_ACCEPT, "*/*"},
{HTTPCli_FIELD_NAME_CONTENT_TYPE, "application/json"},
{NULL, NULL}
};

/* Set request header fields to be send for HTTP request. */
//设置头部到httpClient
HTTPCli_setRequestFields(httpClient, fields);

/* Send POST method request. */
/* Here we are setting moreFlags = 1 as there are some more header fields need to send
other than setted in previous call HTTPCli_setRequestFields() at later stage.
Please refer HTTP Library API documentaion @ref HTTPCli_sendRequest for more information.
*/
moreFlags = 1;
//发送头部信息
//当moreFlags = 1,表明我们需要发送更多的字段

lRetVal = HTTPCli_sendRequest(httpClient, HTTPCli_METHOD_POST, POST_REQUEST_URI, moreFlags);
if(lRetVal < 0)
{
UART_PRINT("Failed to send HTTP POST request header.\n\r");
return lRetVal;
}

sprintf((char *)tmpBuf, "%d", (sizeof(POST_DATA)-1));

/* Here we are setting lastFlag = 1 as it is last header field.
Please refer HTTP Library API documentaion @ref HTTPCli_sendField for more information.
*/
lastFlag = 1;
//发送内容的长度
lRetVal = HTTPCli_sendField(httpClient, HTTPCli_FIELD_NAME_CONTENT_LENGTH, (const char *)tmpBuf, lastFlag);
if(lRetVal < 0)
{
UART_PRINT("Failed to send HTTP POST request header.\n\r");
return lRetVal;
}

/* Send POST data/body */
//发送主体部分 == 内容
lRetVal = HTTPCli_sendRequestBody(httpClient, POST_DATA, (sizeof(POST_DATA)-1));
if(lRetVal < 0)
{
UART_PRINT("Failed to send HTTP POST request body.\n\r");
return lRetVal;
}

//处理响应
lRetVal = readResponse(httpClient);

return lRetVal;
}

static int readResponse(HTTPCli_Handle httpClient) {
long lRetVal = 0;
int bytesRead = 0;
int id = 0;
unsigned long len = 0;
int json = 0;
char *dataBuffer = NULL;
bool moreFlags = 1;

//设置的是响应头
//这个就是一个过滤器,过滤出我们想要的响应头的信息
const char *ids[6] = {
HTTPCli_FIELD_NAME_CONTENT_LENGTH,
HTTPCli_FIELD_NAME_CONTENT_TYPE,
HTTPCli_FIELD_NAME_DATE,
HTTPCli_FIELD_NAME_SERVER,
HTTPCli_FIELD_NAME_TRANSFER_ENCODING,

NULL};

/* Read HTTP POST request status code */

//获取相应状态
//成功是200,其他的不做考虑
lRetVal = HTTPCli_getResponseStatus(httpClient);
if (lRetVal > 0) {
switch (lRetVal) {
case 200:

UART_PRINT("HTTP Status 200\n\r");
//把过滤器跟httpClient关联起来
HTTPCli_setResponseFields(httpClient, (const char **) ids);

//用一个循环来处理响应头
//如果有对应的响应头字段的话,id等于ids的索引
while ((id = HTTPCli_getResponseField(httpClient, (char *) G_Buff,
sizeof(G_Buff), &moreFlags)) != HTTPCli_FIELD_ID_END) {

switch (id) {
case 0:{//HTTPCli_FIELD_NAME_CONTENT_LENGTH
//获取到Content-Length的信息,这个就是主体的长度
//请注意这个不一定是有的,。请注意,而且我们后面是需要这个字段的值
//抓包又抓不到,网上又没有好的调试用具,最后模拟post的数据提交,才发现
//我的服务器一直不发出这个字段。。。导致我很伤心,这个跟服务器是有关系的,后面有讲

len = strtoul((char *)G_Buff, NULL, 10);
UART_PRINT("\r\n%s", HTTPCli_FIELD_NAME_CONTENT_LENGTH);
UART_PRINT(" : %d\r\n", len);
}
break;
case 1: /* HTTPCli_FIELD_NAME_CONTENT_TYPE */
{
UART_PRINT("\r\n%s", HTTPCli_FIELD_NAME_CONTENT_TYPE);
UART_PRINT(" : %s\r\n", G_Buff);
}
break;
case 2: /* HTTPCli_FIELD_NAME_DATE */
{
UART_PRINT("\r\n%s", HTTPCli_FIELD_NAME_DATE);
UART_PRINT(" : %s\r\n", G_Buff);
}
break;
case 3: /* HTTPCli_FIELD_NAME_SERVER */
{
UART_PRINT("\r\n%s", HTTPCli_FIELD_NAME_SERVER);
UART_PRINT(" : %s\r\n", G_Buff);
}
break;
case 4: {/* HTTPCli_FIELD_NAME_TRANSFER_ENCODING */
UART_PRINT("\r\n%s", HTTPCli_FIELD_NAME_TRANSFER_ENCODING);
UART_PRINT(" : %s\r\n", G_Buff);

}
break;

default: {
UART_PRINT("Wrong filter id = %d\r\n",id);
lRetVal = -1;
goto end;
}
}
}
//如果你能获取长度,那么就能使用这个函数获取到主体部分
//不然你得用HTTPCli_readRawResponseBody这个来获取,这个大概 就是获取原始的主体的内容
//HTTPCli_readResponseBody获取到的是经过处理过的主体的内容
bytesRead = HTTPCli_readResponseBody(httpClient, (char *)G_Buff, len, &moreFlags);
if (bytesRead < 0) {
UART_PRINT("Failed to received response body\n\r");
lRetVal = bytesRead;
goto end;
} else {
G_Buff[bytesRead] = 0;
UART_PRINT("\r\nbody:%s \r\n", G_Buff);
}
UART_PRINT("HTTP Status 200 end \r\n");
break;

case 404:
UART_PRINT("File not found. \r\n");
/* Handle response body as per requirement.
Note:
Developers are advised to take appopriate action for HTTP
return status code else flush the response body.
In this example we are flushing response body in default
case for all other than 200 HTTP Status code.
*/
default:
/* Note:
Need to flush received buffer explicitly as library will not do
for next request.Apllication is responsible for reading all the
data.
*/
UART_PRINT("HTTP Status %d\n\r", lRetVal);
break;
}
} else {
UART_PRINT("Failed to receive data from server.\r\n");
goto end;
}

lRetVal = 0;

end:

return lRetVal;
}


服务器代码

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

request.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=utf-8");
PrintWriter out = response.getWriter();
System.out.println("设备发送了数据");
BufferedReader reader = request.getReader();
String line = null;
String text = null ;
//先读一行数据,为什么需要先这样做?因为text的初始值是null,
//执行text += line;后会导致text=“null”+line,所以需要先读一行
//这里可能会有bug存在,
text = reader.readLine();

while((line = reader.readLine()) != null){

text += line;

}
out.write("{\"state\":\"success\"}");
response.setContentLength("{\"state\":\"success\"}".length());
out.flush();
out.close();
System.out.println(text);
return ;
}


六 截图

重要的参考链接,Content-Length讲解/article/1799924.html





服务器主要是这个response.setContentLength("{\"state\":\"success\"}".length());

如果没这句可能 会导致获取Content-Length失败

服务器没有这句话的结果





服务器有这句话的结果



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: