httpclient.c 10 KB

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