• 一个基本的http客户端


    高可用 客户端

    1. httpClient.h

    1. #include
    2. #include
    3. #include
    4. class HttpClient
    5. {
    6. public:
    7. HttpClient(std::string url) : url_(url), port_(0) {}
    8. int write_http(const std::string &method, const std::string &msg);
    9. private:
    10. int get_socket();
    11. int set_sock_timeout(int sockfd, int sec, int ms);
    12. int set_buf_size(int sockfd, int sendsize, int recvsize);
    13. int domain_judge(const char *buf);
    14. int split_url(std::string &url, std::string &host, unsigned short &port);
    15. int host_get_by_name(const char *name);
    16. void print_netstat(int err);
    17. int noblock_connect(int sockfd, struct sockaddr *addrs, int addrlen);
    18. int make_http_head(const char *method, std::string &httpmsg, const std::string &purl);
    19. int make_http_msg(const std::string &method, std::string &msg);
    20. int writen(int connfd, const char *vptr, size_t n);
    21. int recvn_timeout(int connfd, char *vptr, int n, int timeout);
    22. std::string readn(int sockfd, size_t n);
    23. int parse_recvmsg(std::string &recvmsg);
    24. int parse_test(std::string &msg);
    25. private:
    26. std::function<int(std::string &)> parseFunc_;
    27. std::string url_;
    28. std::string host_;
    29. unsigned short port_;
    30. };

    2.httpClient.cpp

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include "httpClient.h"
    16. int HttpClient::make_http_head(const char *method, std::string &httpmsg, const std::string &purl)
    17. {
    18. char headbuf[1024] = {0};
    19. int len = snprintf(headbuf, sizeof(headbuf), "%s %s HTTP/1.1\r\n"
    20. "Content-Type: application/json\r\n"
    21. "Accept: application/json\r\n"
    22. "Host: %s:%d\r\n"
    23. "Connection: Keep-Alive\r\n"
    24. "Content-Length: %d\r\n\r\n",
    25. method,
    26. purl.c_str(),
    27. host_.c_str(),
    28. port_,
    29. static_cast<int>(httpmsg.size()));
    30. httpmsg = headbuf + httpmsg;
    31. return 0;
    32. }
    33. int HttpClient::make_http_msg(const std::string &method, std::string &msg)
    34. {
    35. return make_http_head(method.c_str(), msg, "");
    36. }
    37. int HttpClient::writen(int connfd, const char *vptr, size_t n)
    38. {
    39. int nleft = n, nwrite = 0, retryCont = 0;
    40. char *ptr = const_cast<char *>(vptr);
    41. while (nleft > 0)
    42. {
    43. if ((nwrite = send(connfd, ptr, nleft, MSG_NOSIGNAL)) <= 0)
    44. {
    45. if (retryCont < 100 && (nwrite == 0 || errno == EINTR))
    46. {
    47. nwrite = 0;
    48. ++retryCont;
    49. usleep(10000);
    50. }
    51. else
    52. {
    53. return -1;
    54. }
    55. }
    56. nleft -= nwrite;
    57. ptr += nwrite;
    58. }
    59. return n;
    60. }
    61. int HttpClient::recvn_timeout(int connfd, char *vptr, int n, int sec)
    62. {
    63. int nleft = n;
    64. int nread = 0, retryCnt = 0;
    65. char *ptr = vptr;
    66. fd_set fdset;
    67. struct timeval timeout;
    68. while (nleft > 0)
    69. {
    70. timeout.tv_sec = sec;
    71. timeout.tv_usec = 0;
    72. FD_ZERO(&fdset);
    73. FD_SET(connfd, &fdset);
    74. if (select(connfd + 1, &fdset, nullptr, nullptr, &timeout) <= 0)
    75. {
    76. printf("select fail errno = %d\n", errno);
    77. break;
    78. }
    79. if ((nread = recv(connfd, ptr, nleft, 0)) < 0)
    80. {
    81. if (retryCnt < 50 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR))
    82. {
    83. nread = 0;
    84. ++retryCnt;
    85. usleep(10000);
    86. }
    87. else
    88. {
    89. break;
    90. }
    91. }
    92. else if (nread == 0)
    93. {
    94. break;
    95. }
    96. nleft -= nread;
    97. ptr += nread;
    98. }
    99. return (n - nleft);
    100. }
    101. std::string HttpClient::readn(int sockfd, size_t n)
    102. {
    103. char buf[2048] = {0};
    104. std::string result;
    105. int total = 0;
    106. int byterecv;
    107. do
    108. {
    109. byterecv = recvn_timeout(sockfd, buf, 2048, 5);
    110. if (byterecv <= 0)
    111. {
    112. break;
    113. }
    114. total += byterecv;
    115. result.append(buf, byterecv);
    116. } while (total < n && byterecv == sizeof(buf));
    117. return result;
    118. }
    119. int HttpClient::parse_recvmsg(std::string &recvmsg)
    120. {
    121. std::string ::size_type headend = recvmsg.find("\r\n\r\n");
    122. if (headend == std::string::npos)
    123. {
    124. std::cout << "not found header" << std::endl;
    125. return false;
    126. }
    127. std::string body = recvmsg.substr(headend + 4);
    128. return parseFunc_(body);
    129. }
    130. int HttpClient::split_url(std::string &url, std::string &host, unsigned short &port)
    131. {
    132. if (!url.compare(0, 7, "http://"))
    133. {
    134. url = url.substr(7);
    135. }
    136. if (!url.compare(0, 8, "https://"))
    137. {
    138. url = url.substr(8);
    139. }
    140. size_t slashPos = url.find("/");
    141. if (slashPos != std::string::npos)
    142. {
    143. url = url.substr(0, slashPos);
    144. }
    145. size_t colonPos = url.find(":");
    146. if (colonPos == std::string::npos)
    147. {
    148. host = url;
    149. port = 80;
    150. }
    151. else
    152. {
    153. host = url.substr(0, colonPos);
    154. port = atoi(url.substr(colonPos + 1).c_str());
    155. }
    156. }
    157. int HttpClient::domain_judge(const char *buf)
    158. {
    159. if (nullptr == buf)
    160. {
    161. return false;
    162. }
    163. bool hasChar = false, hasDot = false;
    164. for (size_t i = 0; i < strlen(buf); ++i)
    165. {
    166. if (isalpha(buf[i]))
    167. {
    168. hasChar = true;
    169. continue;
    170. }
    171. if ('.' == buf[i])
    172. {
    173. hasDot = true;
    174. continue;
    175. }
    176. if (hasChar && hasDot)
    177. {
    178. return true;
    179. }
    180. }
    181. return false;
    182. }
    183. int HttpClient::host_get_by_name(const char *name)
    184. {
    185. // char ipaadress[64] = {0};
    186. struct addrinfo hints, *reslut = nullptr, *address = nullptr;
    187. memset(&hints, 0, sizeof(addrinfo));
    188. hints.ai_family = AF_UNSPEC; // ipv4 ipv6
    189. hints.ai_flags = AI_PASSIVE;
    190. hints.ai_socktype = SOCK_STREAM;
    191. int ret = getaddrinfo(name, nullptr, &hints, &reslut);
    192. if (ret != 0)
    193. {
    194. std::cerr << "getaddrinfo err " << gai_strerror(ret) << std::endl;
    195. return ret;
    196. }
    197. for (address = reslut; address != nullptr; address = address->ai_next)
    198. {
    199. if (address->ai_family == AF_INET)
    200. {
    201. struct sockaddr_in *addr = reinterpret_cast<struct sockaddr_in *>(address->ai_addr);
    202. freeaddrinfo(reslut);
    203. return static_cast<int>(addr->sin_addr.s_addr);
    204. }
    205. else if (address->ai_family == AF_INET6)
    206. {
    207. struct sockaddr_in6 *addr = reinterpret_cast<struct sockaddr_in6 *>(address->ai_addr);
    208. continue; // 暂不使用ipv6
    209. }
    210. }
    211. freeaddrinfo(reslut);
    212. return false;
    213. }
    214. int HttpClient::set_buf_size(int sockfd, int sendsize, int recvsize)
    215. {
    216. int ret1 = ::setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<char *>(&sendsize), sizeof(sendsize));
    217. int ret2 = ::setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<char *>(&recvsize), sizeof(recvsize));
    218. return (ret1 == 0 && ret2 == 0) ? 0 : -1;
    219. }
    220. int HttpClient::set_sock_timeout(int sockfd, int sec, int ms)
    221. {
    222. timeval timeout = {sec, ms * 1000};
    223. int ret1 = ::setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char *>(&timeout), sizeof(timeout));
    224. int ret2 = ::setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char *>(&timeout), sizeof(timeout));
    225. return (ret1 == 0 && ret2 == 0) ? 0 : -1;
    226. }
    227. int HttpClient::noblock_connect(int sockfd, struct sockaddr *addrs, int addrlen)
    228. {
    229. struct timeval timeout = {5, 0};
    230. int err = -1;
    231. fd_set fdset;
    232. int flag = 1;
    233. if (ioctl(sockfd, FIONBIO, &flag) != 0)
    234. {
    235. printf("ioctl error\n");
    236. }
    237. int ret = connect(sockfd, addrs, addrlen);
    238. if (-1 == ret)
    239. {
    240. if (EINPROGRESS == errno)
    241. {
    242. FD_ZERO(&fdset);
    243. FD_SET(sockfd, &fdset);
    244. if (select(sockfd + 1, nullptr, &fdset, nullptr, &timeout) > 0)
    245. {
    246. getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, (socklen_t *)&addrlen);
    247. if (0 == err)
    248. {
    249. ret = 0;
    250. }
    251. else
    252. {
    253. ret = -1;
    254. }
    255. }
    256. else
    257. {
    258. ret = -1;
    259. }
    260. }
    261. }
    262. flag = 0;
    263. if (ioctl(sockfd, FIONBIO, &flag) != 0)
    264. {
    265. printf("ioctl error\n");
    266. }
    267. if (ret < 0)
    268. {
    269. print_netstat(err);
    270. }
    271. return ret;
    272. }
    273. void HttpClient::print_netstat(int err)
    274. {
    275. switch (err)
    276. {
    277. case ENETUNREACH: // 网不通
    278. case EHOSTUNREACH:
    279. printf("network is unreachable err[%d]\n", err);
    280. break;
    281. case ECONNREFUSED: // 连接端口被拒绝
    282. printf("no-one listening on the remote address\n");
    283. break;
    284. case ETIMEDOUT: // 网络连接失败,服务器未响应
    285. printf("timeout while attempting connection the server may be to busy\n");
    286. break;
    287. default:
    288. printf("other errno %d\n", err);
    289. break;
    290. }
    291. }
    292. int HttpClient::get_socket()
    293. {
    294. int bufsize = 0x20000; // 128k
    295. int errnoret = -1;
    296. struct sockaddr_in serveraddr;
    297. int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    298. if (sockfd < 0)
    299. {
    300. return -1;
    301. }
    302. memset(&serveraddr, 0, sizeof(serveraddr));
    303. serveraddr.sin_family = AF_INET;
    304. split_url(url_, host_, port_);
    305. if (domain_judge(host_.c_str()))
    306. {
    307. serveraddr.sin_addr.s_addr = host_get_by_name(host_.c_str());
    308. }
    309. else
    310. {
    311. serveraddr.sin_addr.s_addr = inet_addr(host_.c_str());
    312. }
    313. serveraddr.sin_port = htons(port_);
    314. if (set_buf_size(sockfd, bufsize, bufsize) < 0)
    315. {
    316. close(sockfd);
    317. return -1;
    318. }
    319. if (set_sock_timeout(sockfd, 5, 0) < 0)
    320. {
    321. close(sockfd);
    322. return -1;
    323. }
    324. int ret = noblock_connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
    325. if (-1 == ret)
    326. {
    327. close(sockfd);
    328. return -1;
    329. }
    330. return sockfd;
    331. }
    332. int HttpClient::parse_test(std::string &msg)
    333. {
    334. std::cout << msg << std::endl;
    335. return 0;
    336. }
    337. int HttpClient::write_http(const std::string &method, const std::string &msg)
    338. {
    339. std::string httpmsg = msg;
    340. int fd = get_socket();
    341. if (fd < 0)
    342. {
    343. printf("fd is error\n");
    344. return -1;
    345. }
    346. make_http_msg(method, httpmsg);
    347. writen(fd, httpmsg.c_str(), httpmsg.size());
    348. std::string recvmsg = readn(fd, 2048);
    349. std::cout << recvmsg << std::endl;
    350. if (recvmsg.size())
    351. {
    352. parseFunc_ = std::bind(&HttpClient::parse_test, this, std::placeholders::_1);
    353. parse_recvmsg(recvmsg);
    354. }
    355. return 0;
    356. }
    357. void test()
    358. {
    359. HttpClient client("192.168.95.1:8080");
    360. client.write_http("post", "hello\n");
    361. }
    362. int main()
    363. {
    364. test();
    365. return 0;
    366. }

  • 相关阅读:
    看看GPT-4V是怎么开车的,必须围观,大模型真的大有作为 | 万字长文
    高频:spring知识
    WireShark4.0(win10安装教程)
    uniapp开发微信、支付宝小程序订阅消息
    【Arduino+ESP32专题】外部中断的使用
    svg常用属性及动画效果
    B. Different Divisors- Codeforces Round #696 (Div. 2)
    Squeeze-and-Attention Networks for Semantic Segmentation
    【云原生持续交付和自动化测试】5.2 自动化测试和集成测试
    指挥中心实战指挥平台-通信指挥类装备多链路聚合设备解决方案实例
  • 原文地址:https://blog.csdn.net/hfwyydy/article/details/134520052