目录
1.序列化和反序列化
2.HTTP协议
3.编写一个简单的http
3.2.简单的http的使用
3.3.get和post请求传参的区别
4.http的状态码分类
1.序列化和反序列化
1.1.序列化和反序列化的优势
- 序列化将结构体转化为长字符串,便于传输;
- 反序列化在应用层将长字符串转化会结构体,序列化和反序列化都由应用层来处理,传输层只考虑传输的问题;实现了应用层和传输层的解耦
1.2.序列化和反序列化需要那些要求
- 双方都要知道结构体的成员的类型;
- 双方都要知道序列化和反序列化的格式;
双方都要知道的条件不就是一种协议吗
2.HTTP协议
HTTP(超文本传输协议)是一个应用层协议,超文本:含有指向其它文本文件链接的文本
- http没有建立连接和关闭连接,有程序员处理
http协议通常以3到4部分组成:
2.1.URL就是网址
3.编写一个简单的http
3.1查看http的请求
套接字的封装:socket.hpp
#pragma once #include<iostream> #include<cstdlib> #include<sys/socket.h> #include<sys/types.h> #include<netinet/in.h> #include<arpa/inet.h> namespace ns_socket{ class sock{ public: static int Socket() { int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { std::cerr<<"socket"<<std::endl; exit(1); } return sock; } static void Bind(int sock,int port) { struct sockaddr_in local; local.sin_family=AF_INET; local.sin_addr.s_addr=INADDR_ANY; local.sin_port=htons(port); if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0) { std::cerr<<"bind"<<std::endl; exit(2); } } static void Listen(int sock) { if(listen(sock,5)<0) { std::cerr<<"listen"<<std::endl; exit(3); } } static int Accept(int sock) { struct sockaddr_in tmp; socklen_t tlen=sizeof(tmp); int new_sock=accept(sock,(struct sockaddr*)&tmp,&tlen); if(new_sock<0) { std::cerr<<"accept"<<std::endl; exit(4); } return new_sock; } static void Connect(int sock,char* server_ip,char* server_port) { struct sockaddr_in local; local.sin_family=AF_INET; local.sin_addr.s_addr=inet_addr(server_ip); local.sin_port=htons(atoi(server_port)); if(connect(sock,(struct sockaddr*)&local,sizeof(local))<0) { std::cerr<<"connect"<<std::endl; exit(5); } else { std::cout<<"connet success"<<std::endl; } } }; }
服务器端获取http的请求并打印打出来
#include "socket.hpp" #include <string> #include <pthread.h> #include <unistd.h> using namespace ns_socket; using namespace std; #define CAPACITY 1024 * 10 void *HandlerRequest(void *args) { pthread_detach(pthread_self());//线程分离 int new_sock = *((int *)args); //获取http请求 char buffer[CAPACITY]={0}; ssize_t s=recv(new_sock,buffer,sizeof(buffer)-1,0); if(s>0) { buffer[s]=0; cout<<buffer<<endl; } //关闭连接 close(new_sock); }
建立网络通信
int main() { int sock = sock::Socket(); sock::Bind(sock, 8080); sock::Listen(sock); while (1) { int new_sock = sock::Accept(sock); cout << "get a new link" << endl; pthread_t tid; pthread_create(&tid, 0, HandlerRequest, (void *)&new_sock); } return 0; }
执行结果:
3.2.简单的http的使用
前端代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h3>你好吗!</h3>
</body>
</html>
其它的代码和上面的一样,只有这个线程执行的函数不同
#include "socket.hpp"
#include <string>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fstream>
using namespace ns_socket;
using namespace std;
#define CAPACITY 1024 * 10
#define WWWROOT "./wwwroot/"
#define HOME_PAGE "index.html"
void *HandlerRequest(void *args)
{
pthread_detach(pthread_self());
int new_sock = *((int *)args);
// 资源路径
std::string file_path = WWWROOT;
file_path += HOME_PAGE;
//打开资源文件
ifstream in(file_path.c_str());
if (in.is_open())
{
// 获取文件属性
struct stat page_stat;
stat(file_path.c_str(), &page_stat);
//编写http的响应
std::string http_response;
http_response += "http/1.0 200 ok\n";;//状态行
http_response += "Content-Type: text/html\n";//资源是什么类型,查content-type对照表
//资源的长度,字节为单位
http_response += "Content-Longth: ";
http_response += std::to_string(page_stat.st_size);
http_response += "\n";
http_response += "\n"; // 空行
// http的有效载荷,正文
std::string content;
std::string line;
while (std::getline(in, line))
{
content += line;
}
http_response += content;
//把响应发给对端
send(new_sock, http_response.c_str(), http_response.size(), 0);
}
close(new_sock);
}
执行的结果:
3.3.get和post请求传参的区别
3.3.2.<form action="/a/b/handler_from" method="GET">,使用GET传参数;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h5>hello 我是首页!</h5>
<h5>hello 我是表单!</h5>
<form action="/a/b/handler_from" method="GET">
姓名: <input type="text" name="name"><br/>
密码: <input type="password" name="passwd"><br/>
<input type="submit" value="登陆">
</form>
</body>
</html>
使用GET传参数,参数是通过URL传参的;
3.3.2.<form action="/a/b/handler_from" method="POST">,使用POST传参数;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h5>hello 我是首页!</h5>
<h5>hello 我是表单!</h5>
<form action="/a/b/handler_from" method="POST">
姓名: <input type="text" name="name"><br/>
密码: <input type="password" name="passwd"><br/>
<input type="submit" value="登陆">
</form>
</body>
</html>
使用POST传参数,参数是通过正文传参的;
3.3.3.get和post的区别
- get方法通常是做获取网页的,但是也可以用做传参,通过与URL拼接的方式参数传输;post通常用于参数传递,通过http的请求的正文传递给server端;
- get做为参数传参会回显在浏览器的搜索栏,没有通过正文部分传递参数的post的私密性更强,且get使用URL传递参数是有大小现在1024kb,所以在信息不敏感且数量较少的情况下使用get传递参数比较适合;
4.http的状态码分类
数字 | 类型含义 | 类型解释 |
1XX | Information(信息型状态码) | 接受的请求正在处理(不常见,处理的请求通常不会很长) |
2XX | Success(成功状态码) | 类似200 表示请求被处理成功 |
3XX | Redirection(重定向状态码) | 访问某一个服务器,会响应到其他网址;跳转到其他网址 |
4XX | Clinet Error | 类似404 Not Found ,服务器处理不了请求 |
5XX | Server Error | 服务器处理请求失败 |
4.1.重定向如何实现
- location报文配合301永久重定向或者302临时重定向使用
void *HandlerRequest(void *args)
{
pthread_detach(pthread_self());
int new_sock = *((int *)args);
std::string response;
response+="http/1.0 301 Permanently moved\n";
response+="Location: https://www.baidu.com/\n";//location报文配合301永久重定向或者302临时重定向使用
response+="\n";
send(new_sock,response.c_str(),response.size(),0);
close(new_sock);
}
5.cookie和sesion
5.1.为什么需要cookie
当我们登录CSDN后,访问任一一篇文章都是一个另外新的链接,http协议是一个无状态的协议(不会认识用户),为什么不需要我们再输入一次密码,来验证是用户;
cookie中保存用户的私密信息,如果每次都需要我们输入账号密码会让客户端的体验变差
5.2.cookie的思想和自己写一个cookie
- 保证了用户的体验
- 但是cookie保存在浏览器的文件或者内存中,用户能找到那么黑客也可以找到,客户端的问题没法让服务器端解决,只能靠用户不访问恶意链接
5.2.1.自己写一个简单cookie测试
- Set-Cookie添加cookie
- 其他代码和上面一样
void *HandlerRequest(void *args)
{
pthread_detach(pthread_self());
int new_sock = *((int *)args);
char client_requist[1024*10]={0};
recv(new_sock,client_requist,sizeof(client_requist)-1,0);
std::cout<<client_requist<<std::endl;
std::string response;
response+="http/1.0 200 OK\n";
//Set-Cookie添加cookie
response+="Set-Cookie: id=123456\n";
response+="Set-Cookie: password=654321\n";
response+="\n";//空行
send(new_sock,response.c_str(),response.size(),0);
close(new_sock);
}
5.3.sesion(英文会话的意思)
因为如果cookie直接保存用户的账号密码,被盗取就非常危险;
- sesion就是把这些私密信息保存在对端服务器(比如私密信息保存在CSDN的服务器,大型公司通常不容易被入侵),然后返回一个唯一的值保存到浏览器cookie中,即使被盗取也是只有数据被泄漏,账号密码等私密信息没有被泄漏