我是靠谱客的博主 无限小蚂蚁,最近开发中收集的这篇文章主要介绍http协议简析及C++实现HTTP请求http协议简析及C++实现HTTP请求,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

转载自:https://blog.csdn.net/liubailiuestc/article/details/79828896

http协议简析及C++实现HTTP请求

liubailiuestc 2018-04-07 21:12:39

14436

收藏 22

分类专栏: 网络编程 文章标签: HTTP请求 请求报文 TCP握手 C HTTP请求

版权

网络编程 专栏收录该内容

1 篇文章 0 订阅

订阅专栏

http是超文本传输协议,无状态协议(不同批次无法相互识别),无连接协议,工作在应用层,用于完成从万维网服务器传输超文本到本地浏览器的传输协议,完成了文档的快速传输,还能确定传输文档的哪一部分,以及控制哪一部分内容首先显示。

整个http过程由请求和响应构成,a通常承载与TCP协议上。

HTTP完整流程包括四部分:

1.客户机与服务器建立连接;2.客户机发送请求给服务器;3.服务器接收到客户端的请求,发出响应;4.客户端收到请求并处理。

http请求由三部分组成:请求行,首部,请求正文。

请求报文格式为:请求行+首部+空行+实体组成

响应报文格式为:状态行+首部+空行+实体组成

<1>请求行以方法开头,以空格分开,紧随其后的是路径和版本(包括http请求的种类,请求资源的路径,协议的版本号),

格式为:Method Request-URL HTTP-Version CLRF

Method为请求方法(get,post等),Request-URL是统一的资源标识符,HTTP-Version为HTTP协议的版本,CRLF为回车和换行(回车和换行只能出现在结尾,不能再其他地方出现)。

请求方法有:

    GET请求服务器的文档;POST向服务器发送信息;

    PUT从服务器向客户端发送文档;DELETE为删除web网页;

    TRACE为把到达的请求回送;HEAD为请求关于文档的信息,但不是文档本身;OPTIONS询问关于可用的选项;

<2>请求首部为http的头部信息,每一个用rn分割;

常用的首部有:

-----Connection:允许客户端和服务器指定与请求/响应连接有关的选项(长连接,短连接等)

-----Data:提供日期和时间标志

-----MIME-Version:给出了发送端使用的MIME版本

-----Client-IP:描述客户端机器的IP

-----From:提供了客户端用户的E-mail地址

-----Host:给出请求的主机名和端口号

-----Referer:提供了包含当前请求的URL的文档的URL

-----cookie:向服务器传送一个令牌

<3>请求正文为发送给服务器的查询信息(使用get时,body是空的,get只能读取,而post可以写入信息);

"GET / HTTP/1.1rnHost:www.dytt8.netrnConnection:Closernrn"---请求行rn请求首部1rn请求首部2rnrn报文实体内容

响应报文

HTTP/1.1 200 OK
Content-Type: text/html
Content-Location: http://www.dytt8.net/index.htm
Last-Modified: Sat, 07 Apr 2018 02:27:11 GMT
Accept-Ranges: bytes
ETag: "8029cfee17ced31:30d"
Server: Microsoft-IIS/6.0
Date: Sat, 07 Apr 2018 06:18:47 GMT
X-Via: 1.1 localhost.localdomain (random:320992 Fikker/Webcache/3.7.5)
Content-Length: 70109
Connection: close

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns=" http://www.w3.org/1999/xhtml">
<head>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<title>电影天堂_免费电影_迅雷电影下载</title>
<META content="免费电影下载,电影下载,最新电影" name=keywords>
<META content="最好的迅雷电影下载网,分享最新电影,高清电影、综艺、动漫、电视剧等下载!" name=description>

响应报文也包括请求行,请求首部,空行,实体

请求行格式为:http版本+状态码+短语+rn  短语与状态码相对应

请求首部格式为:一系列首部名称:值rn的组合

请求实体为:服务端真正返回的信息

状态编码为:

100-199指定客户端响应的一些动作,请求已被服务接收 200-299表示请求被接受,处理成功 

300-399表示已经移动的文件,重定向,需进一步处理

400-499指定客户端的错误,有语法错误无法实现 500-599指定服务端的错误,服务器未能实现合法的请求

HTTP1.1之后使用了长连接,长连接使数据传输完成后继续保持TCP连接不间断,等待相同域名继续使用这个通道进行数据传输,HTTP1.0使用首部Connection:Keep-alive进行长连接的试验,HTTP1.1之后使用Connection:Close来告诉服务端不使用长连接。但是使用了Connection:Keep-alive这个首部并不代表采用长连接,

在短连接中:每一个请求/响应都需要建立一次TCP连接(三次握手),

长连接模式下:判断数据接收完成的方法有 --1--服务器关闭连接;--2--首部Content-Length判断是否传输完毕,指定了实体正文的长度。

cookie:通过在客户端记录信息确定用户身份,是客户端保存用户信息的一些机制,用于记录用户信息,每次HTTP请求,都会发送响应的cookie到服务端;服务器单从网络请求无法确定用户身份,客户端请求服务器,如果服务器需要记录用户的状态,就通过response向客户端浏览器颁发cookie,浏览器将其保存起来,再次访问时会携带cookie信息,服务器就能通过该信息辨识客户端,进一步可以修改cookie的内容。

session:通过服务端的记录确定用户身份,是在服务端保存到数据结构,用来追踪用户的状态。cookie是通过通行证来检查客户身份,session是通过检查服务器端的客户明细表来确定客户身份,他是客户第一次请求时创建的。一般在浏览完的一定时间内被服务器销毁。

TCP连接的三次握手:

第一次握手:建立连接时客户端发送syn(同步序列编号)包到服务器,进入syn_send状态,等待服务器的确认;

第二次握手:服务器收到syn包,确认客户的syn包(通过发送ack的方式,ack=syn+1),并自己发送一个syn包到客户端,服务器进入syn_recv状态;

第三次握手:客户端收到服务器的syn+ack包,自己向服务端发送确认ack包,ack=syn+1;发送完毕进入ESTABLISH状态,服务端收到确认后也进入到ESTABLISH状态,完成三次握手,客户端开始发送数据到服务端;

采用三次握手是为了避免已失效的连接请求被服务端收到,服务端误以为新连接到来,发送确认ack和syn到客户端,这是客户端收到就可以不作出响应,也就没有新的连接建立。

TCP断开的四次握手:

第一次握手:主动关闭的一方A向对方B发送FIN消息报文,想要关闭连接;

第二次握手:对方B收到这个FIN标志后先向主机A发送确认序号ACK(为了避免对方多次发送FIN消息),然后通知自己对方要关闭连接;

第三次握手:主机B处理完成,向A发送FIN消息,表示自己也愿意关闭这个连接;

第四次握手:主机A收到FIN报文,向B发送一个ACK确认消息,并进入TIME_WITE状态,时间满后自己关闭;

A需要在发送后等待2MSL的时间,一方面是为了怕自己发送的ACK B收不到,B会再次发送FIN+ACK,这样如果提前关闭可能B一直在发这个东西,另一方面避免已经失效的连接请求再次出现,经过2MSL的时间,所以自己时间内产生的报文都将消失。

C++发送HTTP请求:

1.初始化套接字:

 
  1.         WSADATA wsaData;

  2. if (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0)

  3. return true;

  4. else{

  5. cout << "初始化套接字失败" << endl;

  6. return false;

  7. }

2.发送请求:

 
  1.         //step2:通过域名解析主机信息

  2. //包括主机名,别名,地址类型,地址长度和地址列表

  3. struct hostent *hp = gethostbyname(host.c_str());//返回的结构记录了主机的信息

  4. if (hp == NULL){

  5. cout << "域名"<<host<<"解析不成功,可能是网址错误" << endl;

  6. return false;

  7. }

  8. //step3:初始化socket

  9. //指定了协议族(ipv4和16位端口),socket类型(面向连接),协议(TCP传输)

  10. SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  11. if (sock == -1 || sock == -2){

  12. cout << "套接字创建不成功" << endl;

  13. return false;

  14. }

  15. //step4:与socket建立连接

  16. SOCKADDR_IN sa;

  17. sa.sin_family = AF_INET;

  18. sa.sin_port = htons(80);

  19. memcpy(&sa.sin_addr, hp->h_addr, 4);

  20. //建立连接

  21. if (0 != connect(sock, (SOCKADDR*)&sa, sizeof(sa))){

  22. cout << "连接失败" << endl;

  23. return false;

  24. }

  25. int timeout = 60000; //3s

  26. int m = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));

  27. int n = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));

  28. //step5:向socket发送请求

  29. //准备http请求

  30. string request = "GET " + resource + " HTTP/1.1rnHost:" + host + "rnConnection:Closernrn";

  31. //请求数据

  32. if (SOCKET_ERROR == send(sock, request.c_str(), request.size(), 0)){

  33. cout << "请求发送失败" << endl;

  34. closesocket(sock);//需要关闭套接字

  35. return false;

  36. }

  37. cout <<"访问 "<<host+resource<<" 成功" << endl;

  38. //step6:接收socket的请求

  39. //接收数据

  40. int len = MAX_LEN;

  41. char*buff = new char[len];

  42. memset(buff, 0, len);

  43. int bytesRead = 0;//已经读到的长度

  44. int ret = 1;

  45. while (ret>0){

  46. //本次读取到的长度,存储位置为上次读取结束的位置,长度为总长度减去上次的长度

  47. ret = recv(sock, buff + bytesRead, len - bytesRead, 0);

  48. if (ret > 0){//本次读到了数据

  49. bytesRead += ret;

  50. }

  51. if (len - bytesRead < 100){//长度不能满足了,需要重新分配

  52. len = len * 2;

  53. char*newbuff = new char[len];

  54. memset(newbuff, 0, len);

  55. memcpy(newbuff, buff, len / 2);

  56. delete[] buff;

  57. buff = newbuff;

  58. }

  59. cout << "*";

  60. }

  61. buff[bytesRead] = '';//添加结束标志

  62. res = buff;

  63. readSize = bytesRead;

  64. //step7:关闭socket

  65. closesocket(sock);

  66. cout << endl;

  67. cout << "获取 " << host + resource << " 数据成功" << endl;

  68. return true;

最后

以上就是无限小蚂蚁为你收集整理的http协议简析及C++实现HTTP请求http协议简析及C++实现HTTP请求的全部内容,希望文章能够帮你解决http协议简析及C++实现HTTP请求http协议简析及C++实现HTTP请求所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部