目录
1.URL
1.1 作用
IP和找到网络中的主机,IP+端口号可以找到网络中的唯一进程,而URL就是用来确定全网中唯一资源的。
我们所请求的,html,css,js,视频,音频,标签等都称之为资源。网络资源一定存在于全网中一台Linux主机上,Linux和其他OS保存资源的方式都是以文件的形式保存的,单Linux系统表示一个唯一资源的方式就是使用路径。而路径可以视同目录名加分隔符来表示。
1.2 格式
URL的格式为:
通过观察格式,我们发现IP是以域名的方式来呈现的,比如baidu.com,并不是我们所熟悉的点分字符串的形式。
我们可以使用ping指令来查看网络IP的地址。
ping baidu.com
1.3 URL转码
对于URL来说,之所以要进行编码,是因为URL中有些字符会引起歧义。例如,URL参数字符串中如果包含“&”或者“%”势必会造成服务器解析错误,所以需要对其进行编码。
比如当我们在百度中搜索C++的时候,我们发现URL是这样的
这些都是进行转码之后的结果,我们需要关注其中一点:wd
它表示的是我们的搜索内容,可以看到这里的wd=C%2B%2B,%2B表示的就是一个+。
转移规则如下:将需要转码的字符串转成16进制,然后从右到左取四位(不足四位的直接处理),每两位为一位,前面加上%,编码成%XY格式。
还可以使用转码工具来查看。
通常来说,浏览器会自动进行编码,服务器收到后可能会自己进行解码。
2.http协议格式
无论是请求还是响应,基本上http都是按照行为单位进行构建请求或者相应的!无论是请求还是响应都由四部分构成。用户的上网方式其实就是从目标服务器拿到想要的资源,向目标服务器传输数据,本质上在进行IO操作。
2.1 http请求格式
2.2 http响应格式
2.3 解释
其中请求方法有很多,可以是Get等,http的版本有1.1等,状态码我们比较常见的就是404,对该状态码的解释是not fount。
http解包的方式:一行一行读取,知道读到空行,表示之前的都是报头,下面的是报文。
http协议的传送方式:将整个结构看成一个大字符串:xxxx\yyyy\nzzzz\n,空行是一个特殊的字符,通过空行可以将常字符串一分为二。
http如何分用:分用不是http解决的,是具体的应用代码解决的,http需要有接口帮助上层获得参数。
3.http实现网络通信
2.1 网络通信部份
http的传输层协议使用TCP:
#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
#include<unistd.h>
using namespace std;
struct Sock
{
public:
static int Socket()
{
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
cerr<<"socket error"<<endl;
return -1;
}
return sock;
}
static void Bind(int sock,uint16_t port)
{
sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(port);
local.sin_addr.s_addr=INADDR_ANY;
if((bind(sock,(struct sockaddr*)&local,sizeof(local)))<0)
{
cerr<<"bind error"<<endl;
exit(-2);
}
}
static void Listen(int sock)
{
if(listen(sock,5)<0)
{
cerr<<"listen error"<<endl;
exit(-3);
}
}
static int Accept(int sock)
{
sockaddr_in peer;
socklen_t len=sizeof(peer);
int new_sock=accept(sock,(struct sockaddr*)&peer,&len);
if(new_sock<0)
{
cerr<<"accept error"<<endl;
exit(-4);
}
else
{
return new_sock;
}
}
static void Connect(int sock,uint16_t port,string ip)
{
sockaddr_in server;
server.sin_family=AF_INET;
server.sin_port=htons(port);
server.sin_addr.s_addr=inet_addr(ip.c_str());
if((connect(sock,(struct sockaddr*)&server,sizeof(server)))==0)
{
cout<<"connect success"<<endl;
}
else
{
cout<<"connect fail"<<endl;
}
}
};
2.2 服务端
#include"Sock.hpp"
using namespace std;
void Usage(string proc)
{
cout<<proc<<" port"<<endl;
}
void* HandlerHttpRequest(void* args)
{
int sock=*(int*)args;
delete(int*)args;
pthread_detach(pthread_self());
char buffer[1024];
memset(buffer,0,sizeof(buffer));
ssize_t s=recv(sock,buffer,sizeof(buffer),0);
if(s>0)
{
cout<<buffer;
}
close(sock);
return nullptr;
}
int main(int argc,char* argv[])
{
if(argc!=2)
{
Usage(argv[0]);
return -1;
}
uint16_t port=atoi(argv[1]);
int listen_sock=Sock::Socket();
Sock::Bind(listen_sock,port);
Sock::Listen(listen_sock);
while(true)
{
int sock=Sock::Accept(listen_sock);
if(sock>0)
{
pthread_t tid;
int* pram=new int(sock);
pthread_create(&tid,nullptr,HandlerHttpRequest,(void*)pram);
}
}
}
由于没有具体内容,因此空行下的数据层没有内容。
在KV行中,Host代边访问主机,Connection表示连接类型,Cache_Sonrtrol表示缓冲信息,
Usr_agent表示客户端一些信息。
我们可以让服务端来为客户端进行响应:
std::string http_response = "http/1.0 200 OK\n";
http_response += "Content-Type: text/plain\n"; // text/plain,正文是普通的文本
http_response += "\n"; //空行
http_response += "hello Chrome";
send(sock,http_response.c_str(),http_response.size(),0);
此时再用浏览器访问我们的服务器,就可以得到这样一行文本: