http是超文本传输协议,无状态协议(不同批次无法相互识别),无连接协议,工作在应用层,用于完成从万维网服务器传输超文本到本地浏览器的传输协议,完成了文档的快速传输,还能确定传输文档的哪一部分,以及控制哪一部分内容首先显示。
请求报文格式为:请求行+首部+空行+实体组成
响应报文格式为:状态行+首部+空行+实体组成
Method为请求方法(get,post等),Request-URL是统一的资源标识符,HTTP-Version为HTTP协议的版本,CRLF为回车和换行(回车和换行只能出现在结尾,不能再其他地方出现)。
请求方法有:
GET请求服务器的文档;POST向服务器发送信息;
PUT从服务器向客户端发送文档;DELETE为删除web网页;
TRACE为把到达的请求回送;HEAD为请求关于文档的信息,但不是文档本身;OPTIONS询问关于可用的选项;
<2>请求首部为http的头部信息,每一个用\r\n分割;
常用的首部有:
-----Connection:允许客户端和服务器指定与请求/响应连接有关的选项(长连接,短连接等)
-----Data:提供日期和时间标志
-----MIME-Version:给出了发送端使用的MIME版本
-----Client-IP:描述客户端机器的IP
-----From:提供了客户端用户的E-mail地址
-----Host:给出请求的主机名和端口号
-----Referer:提供了包含当前请求的URL的文档的URL
-----cookie:向服务器传送一个令牌
<3>请求正文为发送给服务器的查询信息(使用get时,body是空的,get只能读取,而post可以写入信息);
"GET / HTTP/1.1\r\nHost:www.dytt8.net\r\nConnection:Close\r\n\r\n"---请求行\r\n请求首部1\r\n请求首部2\r\n\r\n报文实体内容
响应报文
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
电影天堂_免费电影_迅雷电影下载
响应报文也包括请求行,请求首部,空行,实体
请求行格式为:http版本+状态码+短语+\r\n 短语与状态码相对应
请求首部格式为:一系列首部名称:值\r\n的组合
请求实体为:服务端真正返回的信息
状态编码为:
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.初始化套接字:
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0)
return true;
else{
cout << "初始化套接字失败" << endl;
return false;
}
2.发送请求:
//step2:通过域名解析主机信息
//包括主机名,别名,地址类型,地址长度和地址列表
struct hostent *hp = gethostbyname(host.c_str());//返回的结构记录了主机的信息
if (hp == NULL){
cout << "域名"<h_addr, 4);
//建立连接
if (0 != connect(sock, (SOCKADDR*)&sa, sizeof(sa))){
cout << "连接失败" << endl;
return false;
}
int timeout = 60000; //3s
int m = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
int n = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
//step5:向socket发送请求
//准备http请求
string request = "GET " + resource + " HTTP/1.1\r\nHost:" + host + "\r\nConnection:Close\r\n\r\n";
//请求数据
if (SOCKET_ERROR == send(sock, request.c_str(), request.size(), 0)){
cout << "请求发送失败" << endl;
closesocket(sock);//需要关闭套接字
return false;
}
cout <<"访问 "<0){
//本次读取到的长度,存储位置为上次读取结束的位置,长度为总长度减去上次的长度
ret = recv(sock, buff + bytesRead, len - bytesRead, 0);
if (ret > 0){//本次读到了数据
bytesRead += ret;
}
if (len - bytesRead < 100){//长度不能满足了,需要重新分配
len = len * 2;
char*newbuff = new char[len];
memset(newbuff, 0, len);
memcpy(newbuff, buff, len / 2);
delete[] buff;
buff = newbuff;
}
cout << "*";
}
buff[bytesRead] = '\0';//添加结束标志
res = buff;
readSize = bytesRead;
//step7:关闭socket
closesocket(sock);
cout << endl;
cout << "获取 " << host + resource << " 数据成功" << endl;
return true;