一.HTTP协议

二.URL的认识










应用层协议往往和端口号是强关联的,比如说http(80),mysql(3306),所以我们不需要体现这个端口号
浏览器会自动添加端口号



当服务器端得到了对应的URL的时候,要将字符重新进行decode(解码)


下面是URL编码的工具,你们可以尝试一下:
https://tool.chinaz.com/Tools/urlencode.aspx
三.HTTP协议请求与响应格式

1.协议的格式(大致了解)
a.Request

本质上http_request就是一个类


b.Response


状态码如404,状态码描述如Not Found
只要我们的数据格式是符合这个协议的,我们就能向浏览器发送请求
2.收发完整性 -- tcp是面向字节流的!
前面已经强调过了,这里我们就不进行强调了
四.http_server封装
1.Socket.hpp的封装

a.Socket设计框架
cpp
#pragma once
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//模板方法模式
//基类, 规定创建套接字的方法
class Socket
{
public:
virtual ~Socket() = default;
virtual int SocketOrDie() = 0;
virtual int SetSocketOpt() = 0;
virtual bool BindOrDie(int listenscokfd) = 0;
virtual bool ListenOrDie(int listenscokfd) = 0;
virtual int Accepter(int listenscokfd) = 0;
virtual void Close(int fd) = 0;
//其他方法,需要时再加
//提供一个创建listensockfd的固定实现
void BuildTcpSocket()
{
SocketOrDie();
SetSocketOpt();
BindOrDie();
ListenOrDie();
}
};
class TcpSocket : public Socket
{
public:
virtual ~TcpSocket() = default;
virtual int SocketOrDie() = 0;
virtual int SetSocketOpt() = 0;
virtual bool BindOrDie(int listenscokfd) = 0;
virtual bool ListenOrDie(int listenscokfd) = 0;
virtual int Accepter(int listenscokfd) = 0;
virtual void Close(int fd) = 0;
private:
};
int main()
{
Socket* sk = new TcpSocket();
sk->BuildTcpSocket();
}

b.Socket的实现
cpp
#pragma once
#include <iostream>
#include <string>
#include <cstdlib>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include "Log.hpp"
#include "Common.hpp"
#include "InetAddr.hpp"
namespace SocketModule
{
using namespace LogModule;
// 模板方法模式
// 基类, 规定创建套接字的方法
class Socket
{
public:
virtual ~Socket() = default;
virtual int SocketOrDie() = 0;
virtual int SetSocketOpt() = 0;
virtual bool BindOrDie(int port) = 0;
virtual bool ListenOrDie() = 0;
virtual int Accepter() = 0;
virtual void Close() = 0;
// 其他方法,需要时再加
// 提供一个创建listensockfd的固定实现
void BuildTcpSocket(int port)
{
SocketOrDie();
SetSocketOpt();
BindOrDie(port);
ListenOrDie();
}
};
class TcpSocket : public Socket
{
public:
TcpSocket():_sockfd(gdefaultsockfd)
{
}
virtual ~TcpSocket()
{
}
virtual int SocketOrDie() override
{
_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
if (_sockfd < 0)
{
LOG(LogLevel::ERROR) << "socket error";
exit(SOCKET_ERR);
}
LOG(LogLevel::DEBUG) << "socket create success: " << _sockfd;
}
virtual int SetSocketOpt()override
{
}
virtual bool BindOrDie(int port)override
{
if(_sockfd == gdefaultsockfd)
{
return false;
}
InetAddr addr(port);
int n = ::bind(_sockfd,addr.NetAddr(),addr.NetAddrLen());
if(n < 0)
{
LOG(LogLevel::ERROR) << "bind error";
exit(BIND_ERR);
}
LOG(LogLevel::DEBUG) << "bind create success: " << _sockfd;
return true;
}
virtual bool ListenOrDie()override
{
if(_sockfd == gdefaultsockfd)
{
return false;
}
int n = ::listen(_sockfd,gbacklog);
if(n < 0)
{
LOG(LogLevel::ERROR) << "listen error";
exit(LISTEN_ERR);
}
LOG(LogLevel::DEBUG) << "listen create success: " << _sockfd;
return true;
}
virtual int Accepter()override
{
}
virtual void Close()override
{
if(_sockfd == gdefaultsockfd)
{
return ;
}
::close(_sockfd);
}
private:
int _sockfd;
};
//for test
int main()
{
Socket* sk = new TcpSocket();
sk->BuildTcpSocket(8080);
}
}



2.TcpServer.hpp的实现
cpp
"Socket.hpp"
#pragma once
#include <iostream>
#include <string>
#include <cstdlib>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include "Log.hpp"
#include "Common.hpp"
#include "InetAddr.hpp"
namespace SocketModule
{
using namespace LogModule;
// 模板方法模式
using SockPtr = std::shared_ptr<Socket>;
// 基类, 规定创建套接字的方法
class Socket
{
public:
virtual ~Socket() = default;
virtual int SocketOrDie() = 0;
virtual int SetSocketOpt() = 0;
virtual bool BindOrDie(int port) = 0;
virtual bool ListenOrDie() = 0;
virtual SockPtr Accepter(InetAddr* client) = 0;
virtual void Close() = 0;
// 其他方法,需要时再加
// 提供一个创建listensockfd的固定实现
void BuildTcpSocket(int port)
{
SocketOrDie();
SetSocketOpt();
BindOrDie(port);
ListenOrDie();
}
};
class TcpSocket : public Socket
{
public:
TcpSocket():_sockfd(gdefaultsockfd)
{
}
TcpSocket(int sockfd):_sockfd(sockfd)
{
}
virtual ~TcpSocket()
{
}
virtual int SocketOrDie() override
{
_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
if (_sockfd < 0)
{
LOG(LogLevel::ERROR) << "socket error";
exit(SOCKET_ERR);
}
LOG(LogLevel::DEBUG) << "socket create success: " << _sockfd;
}
virtual int SetSocketOpt()override
{
}
virtual bool BindOrDie(int port)override
{
if(_sockfd == gdefaultsockfd)
{
return false;
}
InetAddr addr(port);
int n = ::bind(_sockfd,addr.NetAddr(),addr.NetAddrLen());
if(n < 0)
{
LOG(LogLevel::ERROR) << "bind error";
exit(BIND_ERR);
}
LOG(LogLevel::DEBUG) << "bind create success: " << _sockfd;
return true;
}
virtual bool ListenOrDie()override
{
if(_sockfd == gdefaultsockfd)
{
return false;
}
int n = ::listen(_sockfd,gbacklog);
if(n < 0)
{
LOG(LogLevel::ERROR) << "listen error";
exit(LISTEN_ERR);
}
LOG(LogLevel::DEBUG) << "listen create success: " << _sockfd;
return true;
}
//1.文件描述符 2.client info
virtual SockPtr Accepter(InetAddr* client)override
{
if(!client) return nullptr;
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
int newsockfd = ::accept(_sockfd,CONV(&peer),&len);
if(newsockfd < 0)
{
LOG(LogLevel::ERROR) << "accept error";
return nullptr;
}
client->SetAddr(peer,len);
return std::make_shared<TcpSocket>(newsockfd);
}
virtual void Close()override
{
if(_sockfd == gdefaultsockfd)
{
return ;
}
::close(_sockfd);
}
private:
int _sockfd;
};
//for test
int main()
{
Socket* sk = new TcpSocket();
sk->BuildTcpSocket(8080);
}
}



cpp
virtual int Recv(std::string* out)override
{
char buffer[1024];
auto size = ::recv(_sockfd,buffer,sizeof(buffer)-1,0);
if(size > 0)
{
buffer[size] = 0;
*out = buffer;
}
return size;
}
virtual int Send(const std::string& in)override
{
auto size = ::send(_sockfd,in.c_str(),in.size(),0);
return size;
}
send和recv方法实现
cpp
#pragma once
#include <iostream>
#include <memory>
#include <functional>
#include <sys/wait.h>
#include "Socket.hpp"
namespace TcpServerModule
{
using namespace SocketModule;
using namespace LogModule;
using tcphandler_t = std::function<bool(SockPtr, InetAddr)>;
// 它只负责进行IO,不对协议进行任何的处理
class TcpServer
{
public:
TcpServer(int port, tcphandler_t handler) : _listensockp(std::make_unique<TcpSocket>()),
_running(false),
_handler(handler)
{
_listensockp->BuildTcpSocket(port);
}
void Loop()
{
_running = true;
while (_running)
{
InetAddr clientaddr;
// 1.accept
auto sockfd = _listensockp->Accepter(&clientaddr);
if (sockfd == nullptr)
{
continue;
}
// 2.IO处理
LOG(LogLevel::DEBUG) << "get a new client, info is: " << clientaddr.Addr();
pid_t id = fork();
if (id == 0)
{
_listensockp->Close();
if (fork() > 0)
{
exit(0);
}
_handler(sockfd, clientaddr);
exit(0);
}
sockfd->Close();
waitpid(id, nullptr, 0);
}
_running = false;
}
~TcpServer()
{
_listensockp->Close();
}
private:
// 一定要有一个 Listensock
std::unique_ptr<Socket> _listensockp;
bool _running;
tcphandler_t _handler;
};
}


3.HttpServer.hpp的实现
cpp
#pragma once
#include <iostream>
#include <string>
#include "TcpSever.hpp"
using namespace TcpServerModule;
class HttpServer
{
public:
HttpServer(int port):
_tsvr(std::make_unique<TcpServer>(port))
{
}
void Start()
{
_tsvr->InitServer([this](SockPtr sockfd,InetAddr client){
return this->HandlerHttpRequest(sockfd,client);
});
_tsvr->Loop();
}
bool HandlerHttpRequest(SockPtr sockfd,InetAddr client)
{
LOG(LogLevel::DEBUG) << "HttpServer: get a new client: " << sockfd->Fd()
<< " addr info: " << client.Addr();
return true;
}
~HttpServer()
{
}
private:
std::unique_ptr<TcpServer> _tsvr;
};


cpp
bool HandlerHttpRequest(SockPtr sockfd,InetAddr client)
{
LOG(LogLevel::DEBUG) << "HttpServer: get a new client: " << sockfd->Fd()
<< " addr info: " << client.Addr();
std::string http_request;
sockfd->Recv(&http_request);
std::cout << http_request;
return true;
}
我们现在将读到的消息进行打印

4.hello 的网页
cpp
bool HandlerHttpRequest(SockPtr sockfd,InetAddr client)
{
LOG(LogLevel::DEBUG) << "HttpServer: get a new client: " << sockfd->Fd()
<< " addr info: " << client.Addr();
std::string http_request;
//目前我们读取到的是最原始的信息
sockfd->Recv(&http_request);
std::cout << http_request;
//读取请求,进行文本处理
//1.读取请求的完整性 -- 暂时不做了
//2.完整http反序列化,http response序列化...
std::string status_line = "HTTP/1.1 200 OK" + Sep + BlankLine;
std::string body = "<!DOCTYPE html>\
<html>\
<head>\
<meta charset = \"UTF-8\">\
<title> Hello World</title>\
</head>\
<body>\
<p> Hello World</p>\
</body> </html>";
std::string httpresponse = status_line + body;
sockfd->Send(httpresponse);
return true;
}

