小编个人主页详情<—请点击 小编个人gitee代码仓库<—请点击 linux系统编程专栏<—请点击 linux网络编程专栏<—请点击 倘若命中无此运,孤身亦可登昆仑,送给屏幕面前的读者朋友们和小编自己! 
目录
-
- 前言
- 一、两个预备知识
-
- 域名
- url
- 二、http的请求和响应
-
- http请求
- http响应
- 三、三个工具
-
- telnet
- Fiddler Classic
- Postman
- 四、httpserver服务器
-
- HttpServer.hpp
-
- 基础框架
- Start
- ThreadRun
- HttpServer.cc
- 五、测试
- 六、源代码
-
- makefile
- HttpServer.hpp
- HttpServer.cc
- Sock.hpp
- Log.hpp
- 总结
前言
【linux】网络基础(三)TCP服务端网络版本计算器的优化,Json的使用,服务器守护进程化daemon,重谈OSI七层模型——书接上文 详情请点击<——,本文会在上文的基础上进行讲解,所以对上文不了解的读者友友请点击前方的蓝字链接进行学习 本文由小编为大家介绍——【linux】网络基础(四)HTTP协议
一、两个预备知识
域名






url


// 王者荣耀听安主页的网址
https://space.bilibili.com/430044260?spm_id_from=333.788.upinfo.head.click


https://cn.bing.com/search?q=%3A%2F%2F%3F%26%23%3D%40&qs=n&form=QBRE&sp=-1&lq=0&pq=%3A%2F%2F%3F%26%23%3D%40&sc=12-8&sk=&cvid=C39C5BAD36D548818AF5B0A87C56BA0B
https://cn.bing.com/search?q=%3A%2F%2F%3F%26%23%3D%40&qs=n&form=QBRE&sp=-1&lq=0&pq=%3A%2F%2F%3F%26%23%3D%40&sc=12-8&sk=&cvid=C39C5BAD36D548818AF5B0A87C56BA0B
所以我们就在网络上直接搜索url编码在线转换即可 详情请点击<——,将查询的://?&#=@对应编码后的%3A%2F%2F%3F%26%23%3D%40进行解码转换查看,如下无误 
同样的,我们也可以进行编码,如下无误 
二、http的请求和响应

http请求


http响应

三、三个工具
telnet
telnet 39.156.70.239 80


GET / HTTP/1.1





Fiddler Classic




Postman




四、httpserver服务器
HttpServer.hpp
基础框架
#pragma once
#include <iostream>
#include <pthread.h>
#include "Log.hpp"
#include "Socket.hpp"
static const int defaultport = 8080;
class HttpServer;
class ThreadData
{
public:
ThreadData(int fd, HttpServer* s)
: sockfd(fd)
, svr(s)
{}
public:
int sockfd;
HttpServer* svr;
};
class HttpServer
{
public:
HttpServer(uint16_t port = defaultport)
: port_(port)
{}
void Start();
static void* ThreadRun(void* args);
~HttpServer()
{}
private:
uint16_t port_;
Sock listensock_;
};
Start
void Start()
{
listensock_.Socket();
listensock_.Bind(port_);
listensock_.Listen();
for(;;)
{
std::string clientip;
uint16_t clientport;
int sockfd = listensock_.Accept(&clientip, &clientport);
if(sockfd < 0)
continue;
lg(Info, "get a new connect, sockfd: %d, %s:%d",sockfd, clientip.c_str(), clientport);
ThreadData* td = new ThreadData(sockfd, this);
pthread_t tid;
pthread_create(&tid, nullptr, ThreadRun, td);
}
listensock_.Close();
}
ThreadRun

static void* ThreadRun(void* args)
{
pthread_detach(pthread_self());
ThreadData* td = static_cast<ThreadData*>(args);
char buffer[10240];
ssize_t n = recv(td->sockfd, buffer, sizeof(buffer) – 1, 0);
if(n > 0)
{
buffer[n] = 0;
std::cout << buffer << std::endl;
}
close(td->sockfd);
delete td;
return nullptr;
}
HttpServer.cc
#include <iostream>
#include <memory>
#include <unistd.h>
#include "HttpServer.hpp"
int main(int args, char* argv[])
{
if(args != 2)
{
exit(1);
}
uint16_t port = std::stoi(argv[1]);
std::unique_ptr<HttpServer> svr(new HttpServer(port));
svr->Start();
return 0;
}
五、测试



六、源代码
makefile
httpserver:HttpServer.cc
g++ -o $@ $^ -std=c++11 -pthread
.PHONY:clean
clean:
rm -f httpserver
HttpServer.hpp
#pragma once
#include <iostream>
#include <pthread.h>
#include "Log.hpp"
#include "Socket.hpp"
static const int defaultport = 8080;
class HttpServer;
class ThreadData
{
public:
ThreadData(int fd, HttpServer* s)
: sockfd(fd)
, svr(s)
{}
public:
int sockfd;
HttpServer* svr;
};
class HttpServer
{
public:
HttpServer(uint16_t port = defaultport)
: port_(port)
{}
void Start()
{
listensock_.Socket();
listensock_.Bind(port_);
listensock_.Listen();
for(;;)
{
std::string clientip;
uint16_t clientport;
int sockfd = listensock_.Accept(&clientip, &clientport);
if(sockfd < 0)
continue;
lg(Info, "get a new connect, sockfd: %d, %s:%d",sockfd, clientip.c_str(), clientport);
ThreadData* td = new ThreadData(sockfd, this);
pthread_t tid;
pthread_create(&tid, nullptr, ThreadRun, td);
}
listensock_.Close();
}
static void* ThreadRun(void* args)
{
pthread_detach(pthread_self());
ThreadData* td = static_cast<ThreadData*>(args);
char buffer[10240];
ssize_t n = recv(td->sockfd, buffer, sizeof(buffer) – 1, 0);
if(n > 0)
{
buffer[n] = 0;
std::cout << buffer << std::endl;
}
close(td->sockfd);
delete td;
return nullptr;
}
~HttpServer()
{}
private:
uint16_t port_;
Sock listensock_;
};
HttpServer.cc
#include <iostream>
#include <memory>
#include <unistd.h>
#include "HttpServer.hpp"
int main(int args, char* argv[])
{
if(args != 2)
{
exit(1);
}
uint16_t port = std::stoi(argv[1]);
std::unique_ptr<HttpServer> svr(new HttpServer(port));
svr->Start();
return 0;
}
Sock.hpp
#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
const int backlog = 10;
enum{
SocketErr = 1,
BindErr,
ListenErr,
};
class Sock
{
public:
Sock()
{}
void Socket()
{
sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd_ < 0)
{
lg(Fatal, "socket error, %s : %d", strerror(errno), errno);
exit(SocketErr);
}
}
void Bind(uint16_t port)
{
struct sockaddr_in local;
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
socklen_t len = sizeof(local);
if(bind(sockfd_, (struct sockaddr*)&local, len) < 0)
{
lg(Fatal, "bind error, %s : %d", strerror(errno), errno);
exit(BindErr);
}
}
void Listen()
{
if(listen(sockfd_, backlog) < 0)
{
lg(Fatal, "listen error, %s : %d", strerror(errno), errno);
exit(ListenErr);
}
}
int Accept(std::string* clientip, uint16_t* clientport)
{
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
int newfd = accept(sockfd_, (struct sockaddr*)&peer, &len);
if(newfd < 0)
{
lg(Warning, "accept error, %s : %d", strerror(errno), errno);
return –1;
}
char ipstr[128];
inet_ntop(AF_INET, &(peer.sin_addr), ipstr, sizeof(ipstr));
*clientip = ipstr;
*clientport = ntohs(peer.sin_port);
return newfd;
}
bool Connect(const std::string& serverip, uint16_t serverport)
{
struct sockaddr_in peer;
memset(&peer, 0, sizeof(peer));
peer.sin_family = AF_INET;
peer.sin_port = htons(serverport);
inet_pton(AF_INET, serverip.c_str(), &(peer.sin_addr));
socklen_t len = sizeof(peer);
int n = connect(sockfd_, (struct sockaddr*)&peer, len);
if(n == –1)
{
std::cerr << "connect to " << serverip << ':' << serverport << "error" << std::endl;
return false;
}
return true;
}
void Close()
{
if(sockfd_ > 0)
{
close(sockfd_);
}
}
int Fd()
{
return sockfd_;
}
~Sock()
{}
private:
int sockfd_;
};
Log.hpp
#pragma once
#include <iostream>
#include <string>
#include <ctime>
#include <cstdio>
#include <cstdarg>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define SIZE 1024
#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4
#define Screen 1 //输出到屏幕上
#define Onefile 2 //输出到一个文件中
#define Classfile 3 //根据事件等级输出到不同的文件中
#define LogFile "log.txt" //日志名称
class Log
{
public:
Log()
{
printMethod = Screen;
path = "./log/";
}
void Enable(int method) //改变日志打印方式
{
printMethod = method;
}
~Log()
{}
std::string levelToString(int level)
{
switch(level)
{
case Info:
return "Info";
case Debug:
return "Debug";
case Warning:
return "Warning";
case Error:
return "Error";
case Fatal:
return "Fatal";
default:
return "";
}
}
void operator()(int level, const char* format, ...)
{
//默认部分 = 日志等级 + 日志时间
time_t t = time(nullptr);
struct tm* ctime = localtime(&t);
char leftbuffer[SIZE];
snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),
ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,
ctime->tm_hour, ctime->tm_min, ctime->tm_sec);
va_list s;
va_start(s, format);
char rightbuffer[SIZE];
vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
va_end(s);
char logtxt[2 * SIZE];
snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);
printLog(level, logtxt);
}
void printLog(int level, const std::string& logtxt)
{
switch(printMethod)
{
case Screen:
std::cout << logtxt << std::endl;
break;
case Onefile:
printOneFile(LogFile, logtxt);
break;
case Classfile:
printClassFile(level, logtxt);
break;
default:
break;
}
}
void printOneFile(const std::string& logname, const std::string& logtxt)
{
std::string _logname = path + logname;
int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
if(fd < 0)
return;
write(fd, logtxt.c_str(), logtxt.size());
close(fd);
}
void printClassFile(int level, const std::string& logtxt)
{
std::string filename = LogFile;
filename += ".";
filename += levelToString(level);
printOneFile(filename, logtxt);
}
private:
int printMethod;
std::string path;
};
Log lg;
总结
以上就是今天的博客内容啦,希望对读者朋友们有帮助 水滴石穿,坚持就是胜利,读者朋友们可以点个关注 点赞收藏加关注,找到小编不迷路!



