http_clinet.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. #include "stdint.h"
  2. #include "stdio.h"
  3. #include "string.h"
  4. #include "lwip/opt.h"
  5. #include "lwip/arch.h"
  6. #include "lwip/api.h"
  7. #include "lwip/inet.h"
  8. #include "lwip/sockets.h"
  9. #include "lwip/dns.h"
  10. #include "http_client.h"
  11. #include "malloc.h"
  12. uint8_t httpSendBuffer[1024];
  13. uint8_t httpRecvBuffer[512];
  14. #define sendBufSize 1024
  15. #define recvBufSize 512
  16. /**
  17. * @brief 从socket缓存中读取一行http数据
  18. * @param sock: 已经连接到服务器的sock编号
  19. * @param buf: 保存数据的buffer
  20. * @param size: buf的最大可用长度
  21. * @retval 读取到的数据的长度,包括两个字节的换行符
  22. */
  23. int http_getLine(int sock, uint8_t *buf, int size)
  24. {
  25. int i = 0;
  26. char c = '\0';
  27. int n;
  28. while((i < (size - 1)) && (c != '\n'))
  29. {
  30. n = recv(sock, &c, 1, 0);
  31. if(n <= 0) c = '\n';
  32. buf[i++] = c;
  33. }
  34. buf[i] = '\0';
  35. return i; //返回读取的到的数据长度
  36. }
  37. /**
  38. * @brief 解析http响应行
  39. * @param pbuf: 响应行的数据
  40. * @retval 其他值: 返回http请求状态 -1: 解析失败
  41. */
  42. int http_parseRequestLine(uint8_t *pbuf)
  43. {
  44. int b, s, g;
  45. if((strncmp((char *)pbuf, "HTTP/1.1 ", strlen("HTTP/1.1 ")) == 0) || (strncmp((char *)pbuf, "http/1.1 ", strlen("http/1.1 ")) == 0))
  46. {
  47. pbuf += strlen("HTTP/1.1 ");
  48. b = pbuf[0] - '0';
  49. s = pbuf[1] - '0';
  50. g = pbuf[2] - '0';
  51. return (b * 100 + s * 10 + g);
  52. }
  53. return -1;
  54. }
  55. /**
  56. * @brief DNS解析回调函数
  57. * @note 在解析域名成功后,会调用这个函数,然后可以读取到对应的IP地址
  58. * @param name: 域名
  59. * @param host_ip: 域名对应的ip地址
  60. * @param callback_arg: 传递的参数
  61. * @retval None
  62. */
  63. void http_dns_found(const char *name, ip_addr_t *host_ip, void *callback_arg)
  64. {
  65. *(ip_addr_t *)callback_arg = *host_ip;
  66. HTTP_PRINTF("%s:%s\r\n",name, ipaddr_ntoa(host_ip));
  67. }
  68. /**
  69. * @brief 连接到http服务器的函数
  70. * @note 连接到http服务器
  71. * @param host: 服务器的域名或者ip地址
  72. * @param port: 服务器端口号
  73. * @param hostIsIp: host代表的是 域名,还是ip地址 0: host为域名 1: host为ip地址
  74. * @retval -1:连接服务器失败 -2: 域名解析失败 >=0: 连接成功,返回值为 sock编号
  75. */
  76. int http_clientConnectToServer(char *host, int port, int hostIsIp)
  77. {
  78. int timeout;
  79. struct sockaddr_in serverAddr;
  80. int sock = socket(AF_INET, SOCK_STREAM, 0);
  81. if(sock < 0) return -2;
  82. //如果传入的host参数是域名,解析域名
  83. if(hostIsIp == 0)
  84. {
  85. ip_addr_t addr;
  86. addr.addr = 0;
  87. dns_gethostbyname(host, &addr, http_dns_found, &addr);
  88. //等待dns解析完成
  89. timeout = 0;
  90. while((addr.addr == 0) && (timeout < 2000))
  91. {
  92. timeout += 10;
  93. vTaskDelay(100);
  94. }
  95. if(timeout >= 2000)
  96. {
  97. HTTP_PRINTF(("dns get failure \n"));
  98. return -2;
  99. }
  100. serverAddr.sin_addr.s_addr = inet_addr(inet_ntoa(addr));
  101. }
  102. else serverAddr.sin_addr.s_addr = inet_addr((char*)host);
  103. serverAddr.sin_len = sizeof(serverAddr);
  104. serverAddr.sin_family = AF_INET;
  105. serverAddr.sin_port = htons(port);
  106. memset(&serverAddr.sin_zero, 0, sizeof(serverAddr.sin_zero));
  107. //连接服务器
  108. if(connect(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) != 0)
  109. {
  110. HTTP_PRINTF("connect server error \r\n");
  111. return -1;
  112. }
  113. //设置接收数据超时时间
  114. timeout = 3000;
  115. setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(int));
  116. HTTP_PRINTF("connect server success \r\n");
  117. return sock;
  118. }
  119. /**
  120. * @brief 关闭socket端口
  121. * @param sock: 已经连接到服务器的sock编号
  122. */
  123. void http_clientClose(int sock)
  124. {
  125. close(sock);
  126. }
  127. /**
  128. * @brief 连接到发送GET请求
  129. * @note 组装GET数据包,并将GET请求发送出去
  130. * @param sock: 已经连接到服务器的sock编号
  131. * @param host: 服务器的域名或者ip地址
  132. * @param url: 请求资源的地址
  133. * @retval -1: 发送请求失败 1:发送成功
  134. */
  135. int http_clientPacketRequest_GET(int sock, char *host, char *url)
  136. {
  137. int len;
  138. uint8_t* httpSendBuffer = mymalloc(SRAMEX, sendBufSize);
  139. memset(httpSendBuffer, 0, sendBufSize);
  140. //组建请求行
  141. sprintf((char *)httpSendBuffer, "GET ");
  142. if(url == NULL) strcat((char *)httpSendBuffer, "/");
  143. else strcat((char *)httpSendBuffer, url);
  144. strcat((char *)httpSendBuffer, " HTTP/1.1\r\n");
  145. //组建请求头部
  146. strcat((char *)httpSendBuffer, "Host: ");
  147. strcat((char *)httpSendBuffer, host);
  148. strcat((char *)httpSendBuffer, "\r\n");
  149. strcat((char *)httpSendBuffer, "Connection: close\r\n");
  150. strcat((char *)httpSendBuffer, "Accept: application/json\r\n");
  151. strcat((char *)httpSendBuffer, "User-Agent: stm32f207\r\n");
  152. strcat((char *)httpSendBuffer, "Cache-Control: no-cache\r\n");
  153. //添加一个空白行
  154. strcat((char *)httpSendBuffer, "\r\n");
  155. len = strlen((char *)httpSendBuffer);
  156. HTTP_PRINTF("%s", (char *)httpSendBuffer); //
  157. //发送请求报文
  158. len = write(sock, httpSendBuffer, len);
  159. if(len <= 0)
  160. {
  161. myfree(SRAMEX, httpSendBuffer);
  162. return -1;
  163. }
  164. myfree(SRAMEX, httpSendBuffer);
  165. return 1;
  166. }
  167. /**
  168. * @brief http_clientReadResponse_GET
  169. * @note 等待服务器返回GET响应
  170. * @param sock: 已经连接到服务器的sock编号
  171. * @retval -1: 发送请求失败 1:发送成功
  172. */
  173. int http_clientReadResponse_GET(int sock, uint8_t *pbuf, int *datlen)
  174. {
  175. int len, ret;
  176. int length = 0;
  177. uint8_t* httpRecvBuffer = mymalloc(SRAMEX, recvBufSize);
  178. //读取响应行
  179. len = http_getLine(sock, httpRecvBuffer, recvBufSize);
  180. if(len <= 0)
  181. {
  182. myfree(SRAMEX, httpRecvBuffer);
  183. return -1;
  184. }
  185. HTTP_PRINTF("%s", (char *)httpRecvBuffer);
  186. ret = http_parseRequestLine(httpRecvBuffer);
  187. //读取响应头
  188. do
  189. {
  190. len = http_getLine(sock, httpRecvBuffer, recvBufSize);
  191. HTTP_PRINTF("%s", (char *)httpRecvBuffer);
  192. if(len <= 2)
  193. {
  194. if(len == 2) break; //读取到了空行
  195. else
  196. {
  197. myfree(SRAMEX, httpRecvBuffer);
  198. return -1;
  199. }
  200. }
  201. }while(len > 0);
  202. //读取响应主体内容
  203. length = 0;
  204. do
  205. {
  206. len = recv(sock, httpRecvBuffer, recvBufSize, 0);
  207. if(len > 0)
  208. {
  209. memcpy(pbuf + length, httpRecvBuffer, len);
  210. length += len;
  211. }
  212. }while(len > 0);
  213. *datlen = length;
  214. myfree(SRAMEX, httpRecvBuffer);
  215. return ret;
  216. }
  217. /*
  218. * @brief http_clientPacketRequest_POST
  219. * @note 组建和发送POST请求头数据包
  220. * @param sock: 已经连接到服务器的sock编号
  221. * @param host: 服务器域名或者IP地址
  222. * @param url: 请求的资源位置
  223. * @param pbuf: 需要post的数据缓存
  224. * @param datalen 需要post的数据长度
  225. * @retval -1: 发送失败 1:发送成功
  226. */
  227. char httpTmpBuffer[64];
  228. int http_clientPacketRequest_POST(int sock, char *host, char *url, int datalen)
  229. {
  230. int len;
  231. uint8_t* httpSendBuffer = mymalloc(SRAMEX,sendBufSize);
  232. memset(httpSendBuffer, 0, sendBufSize);
  233. //组建请求行
  234. sprintf((char *)httpSendBuffer, "POST ");
  235. if(url == NULL) strcat((char *)httpSendBuffer, "/");
  236. else strcat((char *)httpSendBuffer, url);
  237. strcat((char *)httpSendBuffer, " HTTP/1.1\r\n");
  238. //组建请求头部
  239. memset(httpTmpBuffer, 0, sizeof(httpTmpBuffer));
  240. sprintf(httpTmpBuffer, "Host: %s\r\n", host);
  241. strcat((char *)httpSendBuffer, httpTmpBuffer);
  242. strcat((char *)httpSendBuffer, "Connection: close\r\n");
  243. strcat((char *)httpSendBuffer, "Accept: application/json\r\n"); //
  244. strcat((char *)httpSendBuffer, "User-Agent: stm32f207\r\n");
  245. strcat((char *)httpSendBuffer, "Cache-Control: no-cache\r\n");
  246. strcat((char *)httpSendBuffer, "Content-Type: application/json\r\n");
  247. memset(httpTmpBuffer, 0, sizeof(httpTmpBuffer));
  248. sprintf(httpTmpBuffer, "Content-Length: %d\r\n", datalen);
  249. strcat((char *)httpSendBuffer, httpTmpBuffer);
  250. //添加一个空白行
  251. strcat((char *)httpSendBuffer, "\r\n");
  252. len = strlen((char *)httpSendBuffer);
  253. HTTP_PRINTF("%s", (char *)httpSendBuffer);
  254. //发送请求报文
  255. len = write(sock, httpSendBuffer, len);
  256. if(len <= 0)
  257. {
  258. myfree(SRAMEX, httpSendBuffer);
  259. return -1;
  260. }
  261. myfree(SRAMEX, httpSendBuffer);
  262. return 1;
  263. }
  264. /*
  265. * @brief http_clientPacketBody_POST
  266. * @note 发送post数据
  267. * @param sock: 已经连接到服务器的sock编号
  268. * @param pbuf: 需要post的数据缓存
  269. * @param datalen 需要post的数据长度
  270. * @retval -1: 发送失败 1:发送成功
  271. */
  272. int http_clientPacketBody_POST(int sock, uint8_t *pbuf, int datalen)
  273. {
  274. int len;
  275. while(datalen > 1000)
  276. {
  277. len = write(sock, pbuf, 1000);
  278. if(len <= 0)
  279. {
  280. return -1;
  281. }
  282. datalen -= 1000;
  283. pbuf += 1000;
  284. }
  285. if(datalen > 0)
  286. {
  287. len = write(sock, pbuf, datalen);
  288. if(len <= 0)
  289. {
  290. return -1;
  291. }
  292. }
  293. return 1;
  294. }
  295. /*
  296. * @brief http_clientReadResponse_POST
  297. * @note 读取和解析POST返回的响应
  298. * @param sock: 已经连接到服务器的sock编号
  299. * @retval 响应的返回值
  300. */
  301. int http_clientReadResponse_POST(int sock, uint8_t *pbuf, int *datlen)
  302. {
  303. int len, ret;
  304. int length = 0;
  305. uint8_t* httpRecvBuffer = mymalloc(SRAMEX, recvBufSize);
  306. //读取响应行
  307. len = http_getLine(sock, httpRecvBuffer, recvBufSize);
  308. if(len <= 0)
  309. {
  310. myfree(SRAMEX, httpRecvBuffer);
  311. return -1;
  312. }
  313. HTTP_PRINTF("%s", (char *)httpRecvBuffer);
  314. ret = http_parseRequestLine(httpRecvBuffer);
  315. //读取响应头
  316. do
  317. {
  318. len = http_getLine(sock, httpRecvBuffer, recvBufSize);
  319. HTTP_PRINTF("%s", (char *)httpRecvBuffer);
  320. if(len <= 2)
  321. {
  322. if(len == 2) break; //读取到了空行
  323. else
  324. {
  325. myfree(SRAMEX, httpRecvBuffer);
  326. return -1;
  327. }
  328. }
  329. }while(len > 0);
  330. //读取响应主体内容
  331. length = 0;
  332. do
  333. {
  334. len = recv(sock, httpRecvBuffer, recvBufSize, 0);
  335. if(len > 0)
  336. {
  337. memcpy(pbuf + length, httpRecvBuffer, len);
  338. length += len;
  339. }
  340. }while(len > 0);
  341. *datlen = length;
  342. myfree(SRAMEX, httpRecvBuffer);
  343. return ret;
  344. }
  345. /*
  346. * @brief http_clientGet
  347. * @note 客户端发送GET请求
  348. * @param host: 服务器的域名或者IP地址
  349. * @param url: 访问服务器资源的位置
  350. * @param port: 服务器的端口号
  351. * @param hostIsIp: 第一个参数是域名还是ip地址 0:域名 1: ip地址
  352. * @param pbuf: 接收服务器响应的数据
  353. * @param datalen: 服务器响应数据的长度
  354. * @retval 负值: GET请求异常, 正值: http协议的返回码
  355. */
  356. int http_clientGet(char *host, char *url, uint16_t port, uint8_t hostIsIp, uint8_t *pbuf, int *datalen)
  357. {
  358. int sock = -1, ret;
  359. sock = http_clientConnectToServer(host, port, hostIsIp);
  360. if(sock < 0) goto __httpError;
  361. ret = http_clientPacketRequest_GET(sock, host, url);
  362. if(sock < 0) goto __httpError;
  363. ret = http_clientReadResponse_GET(sock, pbuf, datalen);
  364. if(sock < 0) goto __httpError;
  365. __httpError:
  366. if(sock >= 0)
  367. http_clientClose(sock);
  368. return ret;
  369. }
  370. /*
  371. * @brief http_clientGet
  372. * @note 客户端发送GET请求
  373. * @param host: 服务器的域名或者IP地址
  374. * @param url: 访问服务器资源的位置
  375. * @param port: 服务器的端口号
  376. * @param hostIsIp: 第一个参数是域名还是ip地址 0:域名 1: ip地址
  377. * @param postbuf: 需要发往服务器的数据
  378. * @param postlen: 发送数据的长度
  379. * @param rtnbuf: 接收服务器响应的数据
  380. * @param rtnlen: 服务器响应数据的长度
  381. * @retval 负值: GET请求异常, 正值: http协议的返回码
  382. */
  383. int http_clientPost(char *host, char *url, uint16_t port, uint8_t hostIsIp, uint8_t *postbuf, int postlen, uint8_t *rtnbuf, int *rtnlen)
  384. {
  385. int sock, ret;
  386. sock = http_clientConnectToServer(host, port, hostIsIp);
  387. if(sock < 0) goto __httpError;
  388. ret = http_clientPacketRequest_POST(sock, host, url, postlen);
  389. if(ret < 0) goto __httpError;
  390. ret = http_clientPacketBody_POST(sock, postbuf, postlen);
  391. if(ret < 0) goto __httpError;
  392. ret = http_clientReadResponse_POST(sock, rtnbuf, rtnlen);
  393. __httpError:
  394. if(sock >= 0)
  395. http_clientClose(sock);
  396. return ret;
  397. }