前引
此时在写这篇博客的时候 还是处在重感冒的状态 头晕头疼 状态还不是很好 /(ㄒoㄒ)/~~ 但想着现在看书估计还是可以的 哎 各位还是做事情前有一个好的身体 再做事情吧
这篇博客的话 主要就是 重温一下《Linux多线程服务器编程》前面的几个章节 毕竟现在头疼 让我现在学一些需要深度思考的 需要盘逻辑的 那不如鲨了我吧 现在觉得头这么晕 看一下待会看书还看不看得下去吧 看不下去算了 上午已经忍着头疼刷了三道面试题了 要不今天就不学了… 还是回寝室和朋友一起耍一会 打打游戏算了吧
上面的话是我上午头疼的时候说的 现在已经快晚上10点了 感觉身体好了不少… 刚刚去逛了逛四川老乡群 看到考研的同学在讨论就业单位发的工资 不免心中生起些许波澜 哈哈 看到有之前的学长 本科去虾皮好像是80万的年薪 拿的ssp 也是后端开发岗位的 哈哈 有的时候看看非常优秀的学长 就会再来看看自己
今天尽管头疼 下午晚上好得多了 代码没怎么敲 主要是看书… 看书也只看了160多页 明天应该会好得多了 也就是当闲聊聊聊天罢了
你说不焦虑吧 也不焦虑 你说焦虑吧 哈哈 之前一年多的时候 可能是原来确实没有一个很好的指路人 也没有看到什么很好的路 焦虑也焦虑过了 但现在呢 毕竟自己还是踏踏实实的忙了好久了 平时代码 书籍也还是看的比较多的 对自己的实力 水平认知还是有比较清楚的定位的 但是再怎么样说 再怎么样而言 自己该做的事情还是需要去做 有大把大把的事情还等着我去完成 身前也还有太多太多非常优秀的学长 也希望能像他们一样进入 自己心仪的公司吧 好了 图书馆关门了 就先不写了 明天书里面学到货了再来写了 哈哈
这里也就不贩卖焦虑了哈 毕竟之后入职 实力 + 运气 + 机遇都是机不可少的 希望自己再努力一点点 幸运一点点 老天也一定会祝福的 哈哈
写段话时 昨天是在床上躺过去了 现在身体明显好的多了 但也没有完全好 刚刚在看《Linux多线程服务器编程》的时候 我就在想下一步这个时候应该干什么 是去 马上走下一步 进入到HTTP状态机 开始踏入开始写HTTP协议分析 HTTP服务器 就在这个将个烂就的框架上 继续搭建 还是先把这些需要填补的坑给填上
刚刚就思考了一会 思考完了 就把刚刚自己取的标题是 关于使用智能指针解决内存泄漏问题 正确书写很多地方函数的细节 但想了想就算了 这一篇应该是关于 HTTP 文件部署的 说一下原因吧 就个人而言 这种感觉是什么 就是穿着西装领带和一双崭新的皮鞋打算去一个大厅见非常重要的领导 但是由于是步行前去 且路途较遥远 时间也十分可贵 走在路中间 自己的皮鞋已经烂的差不多了 前面已经破了多少个洞了 但是呢 精力是有限的 时间也是有限的 是现在马上去换一双新皮鞋继续走呢 回来发现自己还是停在原地 心中焦躁呢急忙忙的赶过去呢 还是不管三七二十一 去了快走到位了 再不骄不躁的 一点点整理自己的衣服 买双崭新的皮鞋 去宾馆里面好好的洗个热水澡 轻装上阵 知道自己已经在目的地了 这个时候只需要耐心点 打理好一切需要打理的地方就好了
性格如此 所以我也选择了后者 那么由此 又要拿起那本小黑人击剑书了 因为那本书籍里面讲解HTTP状态转移里面写的特别详细 特别多 我先自己不看源码 自己看看书琢磨琢磨怎么写 后面再看看muduo库里面是怎么处理的
(六)跌跌撞撞奔向HTTP状态机 学习途中拾慧纠正过往细节偏差
文章标题后半段取成这样的原因 是我在吃完饭路上回来的时候 仔细看了看epoll 中的ET(Edge Trigger) LT(Level Trigger) 有什么差别 之后就发现自己之前对于ET工作模式中的recv使用是错误的 而且综合下来 应该之后会改成LT工作模式了 详细原因可见下面的博客推荐
为何 epoll 的 ET 模式一定要设置为非阻塞IO Epoll之ET、LT模式
1、工欲行其事 必先利其器 buffer横空出世
先从buffer开始吧 因为HTTP协议 有可能一条命令发送不完 需要有接受Buffer 或者是 发送消息的时候 操作系统不能全部发送完 都需要Buffer来存储状态
所以先从Buffer下手吧 之后可以陆陆续续的补充
写到这里的时候 一个简陋的HTTP服务器已经出来了 并且也已经经过了simple test了 现在也已经9:36了 感觉现在目前写这个WebServer的动力好像已经没有之前那么足了哈 哈哈 但确实是这样的
就好像如果打游戏 你很清楚打游戏的机会其实好像没有那么多 但如果打游戏变成了职业 要靠这个为生 我相信打游戏这个事情 也不再是刚开始确实沉浸在游戏之中那么快乐了
因为这个项目 是我之后要实习面试的项目 是要之后与面试官谈论的项目 需要鲁棒性 需要考虑很多细节 尽管muduo是一个内网用的网络库 不需要考虑很多的安全性的考虑 但是至少这个muduo库的源码 至少对于http服务器的部分 至少是需要看3-4遍 去专研细节 去雕刻细节的 书籍的话 也是至少真的是需要把每一章节 每一个段落写的意思去看懂的
毕竟腾讯、阿里这样的大厂也是非常重视项目的 所以我在项目上面也是需要特别上心吧 做这个项目 刚刚在输入127.0.0.1:2022 忽然出现的网页 是我写在博客主页左下角的自定义的html 的时候 欣喜了大概十分钟后 就保持了和原来一样的沉静
这几天的写代码的效率不是很高 但是也不可能每天的效率都是非常高的 因为生活中总是有这样有那样的事情需要去处理
好了 上面聊了点闲聊 写这个系列博客总是需要把做每一部分的心路历程写写吧 也总不能当一个没有感情的码字人吧 生活是需要色彩的 博客也是需要色彩的
Http部分 有些部分是我自己大概想了想怎么实现的 我就这样去实现了 这段时间 查阅的博客啊 研究那些变量命名 自己也研究了一段时间 我也没有想到 到4月1日的晚上 自己的HTTP服务器初代 就出世了
我猜测啊 这个系列博客 应该大概是会出到12篇左右 就会结束了 因为后面都是不断地去完善这个项目了 例如我现在想到的 定时池/支持高IO的日记库 这些都是需要去实现的
当然 之前的历史遗留问题也没有解决 内存泄漏 析构问题 有可能存在的竞态问题 我都没有仔细去思考过 对于目前用锁的地方 要不就是特别明显 我都觉得需要用锁去保护 要不就是参考了muduo库 自己也思考了一下确实需要用 自己才用
总之就是这些 当前进度总结部分就先到这里吧
buffer部分的话 思路是看书后 实现的 1、prependindex 2、readindex 3、writeindex
底层实现的话 就是用的高效的vector 至于内存扩展 就是vector自己的事情了 每次确保内存够用 不够用的话 vector resize就行了 至于vector resize的机制 也就是两倍于之前的内存 预留空间的方案 剩下的话 好像也没有什么多余有技术含量的东西了 哦 还有prepend 随着写入、读入的数据越来越多 指针是越来越靠前 如果readindex = writeindex 也就是读取缓冲区的数据读完了 就会回到之前的预设的 8 kPrePendIndex 就是这样一个思路 之后与数据相写的 除了有少量的能够直接发送完的数据被直接发送 剩下的都交由buffer 来负责 存储状态
1、buffer.h
#ifndef TINY_MUDUO_BUFFER_H_
#define TINY_MUDUO_BUFFER_H_
#include <vector>
#include <algorithm>
#include <string>
#include <assert.h>
using std::string;
namespace tiny_muduo {
static const int kPrePendIndex = 8;
class Buffer {
public:
Buffer() : buffer_(1024), read_index_(kPrePendIndex), write_index_(kPrePendIndex) {
}
~Buffer() {}
int ReadFd(int fd);
char* begin() { return &*buffer_.begin(); };
const char* begin() const { return &*buffer_.begin(); };
char* beginread() { return begin() + read_index_; }
const char* beginread() const { return begin() + read_index_; }
char* beginwrite() { return begin() + write_index_; }
const char* beginwrite() const { return begin() + write_index_; }
void Append(const char* message, int len) {
MakeSureEnoughStorage(len);
std::copy(message, message + len, beginwrite());
write_index_ += len;
}
void Append(const string& message) {
Append(message.data(), message.size());
}
void Retrieve(int len) {
if (len + read_index_ != write_index_) {
read_index_ = read_index_ + len;
} else {
write_index_ = kPrePendIndex;
read_index_ = write_index_;
}
}
void RetrieveUntilIndex(const char* index) {
assert(beginwrite() >= index);
read_index_ += index - beginread();
}
void RetrieveAll() {
write_index_ = kPrePendIndex;
read_index_ = write_index_;
}
string RetrieveAsString(int len) {
assert(read_index_ + len <= write_index_);
string ret = std::move(PeekAsString(len));
Retrieve(len);
return ret;
}
string RetrieveAllAsString() {
string ret = std::move(PeekAllAsString());
RetrieveAll();
return ret;
}
const char* Peek() const {
return beginread();
}
char* Peek() {
return beginread();
}
string PeekAsString(int len) {
return string(beginread(), beginread() + len);
}
string PeekAllAsString() {
return string(beginread(), beginwrite());
}
int readablebytes() const { return write_index_ - read_index_; }
int writablebytes() const { return buffer_.capacity() - write_index_; }
int prependablebytes() const { return read_index_; }
void MakeSureEnoughStorage(int len) {
if (writablebytes() >= len) return;
if (writablebytes() + prependablebytes() >= kPrePendIndex + len) {
std::copy(beginread(), beginwrite(), begin() + kPrePendIndex);
write_index_ = 8 + readablebytes();
read_index_ = 8;
} else {
buffer_.resize(buffer_.size() + len);
}
}
private:
std::vector<char> buffer_;
int read_index_;
int write_index_;
};
}
#endif
2、buffer.cc
#include "buffer.h"
#include <sys/uio.h>
using namespace tiny_muduo;
int Buffer::ReadFd(int fd) {
char extrabuf[65536] = {0};
struct iovec iv[2];
const int writable = writablebytes();
iv[0].iov_base = beginwrite();
iv[0].iov_len = writable;
iv[1].iov_base = extrabuf;
iv[1].iov_len = sizeof(extrabuf);
const int iovcnt = (writable < static_cast<int>(sizeof(extrabuf)) ? 2 : 1);
int readn = readv(fd, iv, iovcnt);
if (readn < 0) {
assert(readn >= 0);
}
else if (readn <= writable) {
write_index_ += readn;
} else {
write_index_ = buffer_.size();
Append(extrabuf, readn - writable);
}
return readn;
}
2、大摇大摆走下HTTP状态机 抽丝剥解底层逻辑
其实之前的时候 估计是人处在重感冒 现在都还有一点没好 嗓子疼 然后呢 自己分析起来觉得有点点困难 现在看起来觉得 底层逻辑就这么点 没什么难的 主体框架基本上都是那么多 也就是在框架上搭桥梁而已
那我们就开始来分析一下 新增的几个文件吧
1、httpserver.cc 2、httprequest.cc 3、httpresponse.cc 4、httpcontent.cc httpserver.cc 很典型的 跟之前的echo.cc差不多 就是http服务器框架 其中有负责什么连接函数啊 消息到来处理函数啊 设置几个回调 然后基本处理源头就在这里了 它直接处理的对象呢 就是httpcontent httpcontent.cc 这个是 直接就在每个Tcpconnect 内置的 里面包含了有Httprequest 还有当前的分析机状态 走到哪一步了 也就是Http分析的呈现体而已 值得一说的是 这里我们相较于muduo 更精细化的设置了index_ 也就是读入的每一个字符 只要是读入过的 就不再重复分析 这个工作就是parseline 核心就是检测遇没有遇到\r \n 这两个字符 遇到了 则把每一行交给 httprequest去处理 httprequest.cc 分析主干部分 分析工作就交给他了 里面也有成员负责记录 协议版本 请求命令是Get啊 还是Post 还是其他的 还有url的请求地址 反正 header requestline 每让httpcontent 分析完一行 就交给他来分析 并且由此来更新目前 状态机状态 httpresponse.cc 当然就是我们的回应部分 里面包括很多 回应的版本号 状态码 状态消息是什么 以及一些回应头部 都在httpresponse中记录 而且最后我们消息处理的交互 也就是让一个栈中变量Httpresponse 在临走时 填充好也是一个临时栈中变量的buffer 并且送回去 发送消息 还有一些罗里吧嗦的一些文件 有些是我一时兴起想加的 还有的 好吧就是我想加的 方便使用 而且与众不同一点…(尽管好像没有什么用) 特别注意的是 http最后的填充的回调函数 是在main.cc中的 也就是在main.cc一开始就注册了 main.cc中的回调 之后填充buffer的时候 调用的也就是这里的函数
3、三回创 HTTP服务器横空出世(仅罗列部分 更新、新添加代码)
由于篇幅限制 主要是为了抛出更多冗杂内容 所以就不再把与上篇博客相同的代码罗列出来了
相同的部分代码 就是主体框架 就没有在动过了 要动的代码都是涉及http服务器正常运行 适量的增加删除 和之后 增加的文件一起 才最后实现的http服务器
本篇就不贴出来了 望见谅 如果想要看上一篇博客的全代码的话 还请劳烦点下面链接转战上篇博客 从零开始自制实现WebServer(五)---- 浅沿芳草鲜花小路静心踱步 拨云见雾终见多线程ThreadPool
1、main.cc(更新)
#include <stdio.h>
#include <string>
#include "eventloop.h"
#include "address.h"
#include "httpserver.h"
#include "httprequest.h"
#include "httpresponse.h"
#include "httpresponsefile.h"
using namespace tiny_muduo;
using tiny_muduo::Method;
using tiny_muduo::HttpStatusCode;
void HttpResponseCallback(const HttpRequest& request, HttpResponse& response) {
if (request.method() != kGet) {
response.SetStatusCode(k400BadRequest);
response.SetStatusMessage("Bad Request");
response.SetCloseConnection(true);
return;
}
{
const string& path = request.path();
if (path == "/") {
response.SetStatusCode(k200OK);
response.SetBodyType("text/html");
response.SetBody(love6_website);
} else if (path == "/hello") {
response.SetStatusCode(k200OK);
response.SetBodyType("text/plain");
response.SetBody("Hello, world!\n");
} else if (path == "/favicon") {
response.SetStatusCode(k200OK);
response.SetBodyType("image/png");
response.SetBody(string(favicon, sizeof(favicon)));
} else {
response.SetStatusCode(k404NotFound);
response.SetStatusMessage("Not Found");
response.SetBody("Sorry, Not Found\n");
response.SetCloseConnection(true);
return;
}
}
}
int main( int argc , char* argv[] )
{
if (argc <= 1)
{
printf( "Usage: %s portname\n", argv[0] );
return 0;
}
EventLoop loop;
Address listen_address(argv[1]);
HttpServer server(&loop, listen_address);
server.SetHttpResponseCallback(HttpResponseCallback);
server.Start();
loop.Loop();
return 0;
}
2、tcpconnection.h(更新)
#ifndef TINY_MUDUO_TCPCONNECTION_H_
#define TINY_MUDUO_TCPCONNECTION_H_
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string>
#include "callback.h"
#include "channel.h"
#include "buffer.h"
#include "httpcontent.h"
using std::string;
namespace tiny_muduo {
class EventLoop;
class TcpConnection {
public:
TcpConnection(EventLoop* loop,int connfd);
~TcpConnection();
void SetConnectionCallback(const ConnectionCallback& callback) {
connection_callback_ = callback;
}
void SetMessageCallback(const MessageCallback& callback) {
message_callback_ = callback;
}
void ConnectionEstablished() {
channel_->EnableReading();
connection_callback_(this, &input_buffer_);
}
HttpContent* GetHttpContent() {
return &content_;
}
void Shutdown() {
if (!channel_->IsWriting()) {
shutdown_ = true;
::shutdown(fd_, SHUT_WR);
}
}
bool IsShutdown() const { return shutdown_; }
void HandleMessage();
void HandleWrite();
void Send(Buffer* buffer);
void Send(const string& str);
void Send(const char* message, int len);
void Send(const char* message) { Send(message, strlen(message)); }
private:
EventLoop* loop_;
int fd_;
bool shutdown_;
Channel* channel_;
Buffer input_buffer_;
Buffer output_buffer_;
HttpContent content_;
ConnectionCallback connection_callback_;
MessageCallback message_callback_;
};
}
#endif
2、tcpconnection.cc(更新)
#include "tcpconnection.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <assert.h>
#include "channel.h"
#include "buffer.h"
using namespace tiny_muduo;
TcpConnection::TcpConnection(EventLoop* loop, int connfd)
: loop_(loop),
fd_(connfd),
shutdown_(false),
channel_(new Channel(loop_, fd_)) {
channel_->SetReadCallback(std::bind(&TcpConnection::HandleMessage, this));
channel_->SetWriteCallback(std::bind(&TcpConnection::HandleWrite, this));
}
void TcpConnection::HandleMessage() {
int read_size = input_buffer_.ReadFd(fd_);
if (read_size > 0)
message_callback_(this, &input_buffer_);
}
void TcpConnection::HandleWrite() {
int len = output_buffer_.readablebytes();
int remaining = len;
int send_size = send(fd_, output_buffer_.Peek(), remaining, 0);
remaining -= send_size;
assert(remaining <= len);
if (!remaining) {
channel_->DisableWriting();
}
}
void TcpConnection::Send(const char* message, int len) {
int remaining = len;
int send_size = 0;
if (!channel_->IsWriting() && output_buffer_.readablebytes() == 0) {
send_size = send(fd_, message, len, 0);
remaining -= send_size;
}
assert(remaining <= len);
if (remaining > 0) {
output_buffer_.Append(message + send_size, remaining);
if (!channel_->IsWriting()) {
channel_->EnableWriting();
}
}
}
void TcpConnection::Send(Buffer* buffer) {
Send(buffer->Peek(), buffer->readablebytes());
}
void TcpConnection::Send(const string& message) {
Send(message.data(), sizeof(message.size()));
}
3、epoller.h(更新)
#ifndef TINY_MUDUO_EPOLLER_H_
#define TINY_MUDUO_EPOLLER_H_
#include <sys/epoll.h>
#include <vector>
namespace {
const int kMaxEvents = 8;
}
namespace tiny_muduo {
class Channel;
class Epoller {
public:
typedef std::vector<epoll_event> Events;
typedef std::vector<Channel*> Channels;
Epoller();
void Poll(Channels& channels);
int EpollWait() { return epoll_wait(epollfd_, &*events_.begin(), kMaxEvents, -1); }
int SetNonBlocking(int fd);
void FillActiveChannels(int eventnums, Channels& channels);
void Update(Channel* channel);
void UpdateChannel(int operation, Channel* channel);
private:
int epollfd_;
Events events_;
};
}
#endif
3、epoller.cc(更新)
#include "epoller.h"
#include <string.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include "channel.h"
using namespace tiny_muduo;
Epoller::Epoller()
: epollfd_(epoll_create(kMaxEvents)),
events_(kMaxEvents) {
}
void Epoller::Poll(Channels& channels) {
int eventnums = EpollWait();
FillActiveChannels(eventnums, channels);
}
void Epoller::FillActiveChannels(int eventnums, Channels& channels) {
for (int i = 0; i < eventnums; ++i) {
Channel* ptr = static_cast<Channel*> (events_[i].data.ptr);
ptr->SetReceivedEvents(events_[i].events);
channels.emplace_back(ptr);
}
}
int Epoller::SetNonBlocking(int fd) {
int old_state = fcntl(fd, F_GETFL);
int new_state = old_state | O_NONBLOCK;
fcntl(fd, F_SETFL, new_state);
return new_state;
}
void Epoller::Update(Channel* channel) {
int op = 0, events = channel->events();
ChannelState state = channel->state();
if (state == kNew || state == kDeleted) {
channel->SetChannelState(kAdded);
if (events & EPOLLIN) {
op = EPOLL_CTL_ADD;
SetNonBlocking(channel->fd());
} else if (events & EPOLLRDHUP) {
op = EPOLL_CTL_DEL;
} else {
}
} else {
op = EPOLL_CTL_MOD;
}
UpdateChannel(op, channel);
}
void Epoller::UpdateChannel(int operation, Channel* channel)
{
struct epoll_event event;
memset(&event, '\0', sizeof(struct epoll_event));
event.events = channel->events();
event.data.ptr = static_cast<void*>(channel);
epoll_ctl(epollfd_, operation, channel->fd(), &event);
return;
}
4、channel.h(更新)
#ifndef TINY_MUDUO_CHANNEL_H_
#define TINY_MUDUO_CHANNEL_H_
#include <sys/epoll.h>
#include "eventloop.h"
#include "callback.h"
namespace tiny_muduo {
enum ChannelState {
kNew,
kAdded,
kDeleted
};
class Channel {
public:
Channel(EventLoop* loop, const int& fd);
~Channel();
void HandleEvent();
void SetReadCallback(const ReadCallback& callback) {
read_callback_ = callback;
}
void SetWriteCallback(const WriteCallback& callback) {
write_callback_ = callback;
}
void EnableReading() {
events_ |= EPOLLIN;
Update();
}
void EnableWriting() {
events_ |= EPOLLOUT;
Update();
}
void DisableWriting() {
events_ &= ~EPOLLOUT;
Update();
}
void RemoveFd() {
}
void Update() {
loop_->Update(this);
}
void SetReceivedEvents(int events) {
recv_events_ = events;
}
void SetChannelState(ChannelState state) {
state_ = state;
}
int fd() { return fd_; }
int events() { return events_; }
int recv_events() { return recv_events_; }
ChannelState state() { return state_; }
bool IsWriting() { return events_ & EPOLLOUT; }
bool IsReading() { return events_ & EPOLLIN; }
private:
EventLoop* loop_;
int fd_;
int events_;
int recv_events_;
ChannelState state_;
ReadCallback read_callback_;
WriteCallback write_callback_;
};
}
#endif
4、channel.cc(更新)
#include "channel.h"
#include <sys/epoll.h>
using namespace tiny_muduo;
Channel::Channel(EventLoop* loop,
const int& fd)
: loop_(loop),
fd_(fd),
events_(0),
recv_events_(0) {
}
void Channel::HandleEvent() {
if (recv_events_ & EPOLLIN) {
read_callback_();
} else if (recv_events_ & EPOLLOUT) {
write_callback_();
} else {
}
}
5、buffer.h(新添加)
#ifndef TINY_MUDUO_BUFFER_H_
#define TINY_MUDUO_BUFFER_H_
#include <vector>
#include <algorithm>
#include <string>
#include <assert.h>
using std::string;
namespace tiny_muduo {
static const int kPrePendIndex = 8;
class Buffer {
public:
Buffer() : buffer_(1024), read_index_(kPrePendIndex), write_index_(kPrePendIndex) {
}
~Buffer() {}
int ReadFd(int fd);
char* begin() { return &*buffer_.begin(); };
const char* begin() const { return &*buffer_.begin(); };
char* beginread() { return begin() + read_index_; }
const char* beginread() const { return begin() + read_index_; }
char* beginwrite() { return begin() + write_index_; }
const char* beginwrite() const { return begin() + write_index_; }
void Append(const char* message, int len) {
MakeSureEnoughStorage(len);
std::copy(message, message + len, beginwrite());
write_index_ += len;
}
void Append(const string& message) {
Append(message.data(), message.size());
}
void Retrieve(int len) {
if (len + read_index_ != write_index_) {
read_index_ = read_index_ + len;
} else {
write_index_ = kPrePendIndex;
read_index_ = write_index_;
}
}
void RetrieveUntilIndex(const char* index) {
assert(beginwrite() >= index);
read_index_ += index - beginread();
}
void RetrieveAll() {
write_index_ = kPrePendIndex;
read_index_ = write_index_;
}
string RetrieveAsString(int len) {
assert(read_index_ + len <= write_index_);
string ret = std::move(PeekAsString(len));
Retrieve(len);
return ret;
}
string RetrieveAllAsString() {
string ret = std::move(PeekAllAsString());
RetrieveAll();
return ret;
}
const char* Peek() const {
return beginread();
}
char* Peek() {
return beginread();
}
string PeekAsString(int len) {
return string(beginread(), beginread() + len);
}
string PeekAllAsString() {
return string(beginread(), beginwrite());
}
int readablebytes() const { return write_index_ - read_index_; }
int writablebytes() const { return buffer_.capacity() - write_index_; }
int prependablebytes() const { return read_index_; }
void MakeSureEnoughStorage(int len) {
if (writablebytes() >= len) return;
if (writablebytes() + prependablebytes() >= kPrePendIndex + len) {
std::copy(beginread(), beginwrite(), begin() + kPrePendIndex);
write_index_ = 8 + readablebytes();
read_index_ = 8;
} else {
buffer_.resize(buffer_.size() + len);
}
}
private:
std::vector<char> buffer_;
int read_index_;
int write_index_;
};
}
#endif
5、buffer.cc(新添加)
#include "buffer.h"
#include <sys/uio.h>
using namespace tiny_muduo;
int Buffer::ReadFd(int fd) {
char extrabuf[65536] = {0};
struct iovec iv[2];
const int writable = writablebytes();
iv[0].iov_base = beginwrite();
iv[0].iov_len = writable;
iv[1].iov_base = extrabuf;
iv[1].iov_len = sizeof(extrabuf);
const int iovcnt = (writable < static_cast<int>(sizeof(extrabuf)) ? 2 : 1);
int readn = readv(fd, iv, iovcnt);
if (readn < 0) {
assert(readn >= 0);
}
else if (readn <= writable) {
write_index_ += readn;
} else {
write_index_ = buffer_.size();
Append(extrabuf, readn - writable);
}
return readn;
}
6、httpserver.h(新添加)
#ifndef TINY_MUDUO_HTTPSERVER_H_
#define TINY_MUDUO_HTTPSERVER_H_
#include <stdio.h>
#include <functional>
#include <utility>
#include "tcpserver.h"
#include "tcpconnection.h"
#include "buffer.h"
#include "httpcontent.h"
#include "httprequest.h"
#include "httpresponse.h"
using tiny_muduo::HttpStatusCode;
namespace tiny_muduo {
static const int kThreadNums = 8;
class EventLoop;
class HttpServer{
typedef std::function<void (const HttpRequest&, HttpResponse&)> HttpResponseCallback;
public:
HttpServer(EventLoop* loop, const Address& address);
~HttpServer();
void Start() {
server_.Start();
}
void HttpDefaultCallback(const HttpRequest& request, HttpResponse& response) {
response.SetStatusCode(k404NotFound);
response.SetStatusMessage("Not Found");
response.SetCloseConnection(true);
}
void ConnectionCallback(TcpConnection* connection) {
printf("HttpServer has New Conneciton");
}
void MessageCallback(TcpConnection* connection, Buffer* buffer);
void SetHttpResponseCallback(const HttpResponseCallback& response_callback) {
response_callback_ = std::move(response_callback);
}
void DealWithRequest(const HttpRequest& request, TcpConnection* connection);
private:
EventLoop* loop_;
TcpServer server_;
HttpResponseCallback response_callback_;
};
}
#endif
6、httpserver.cc(新添加)
#include "httpserver.h"
#include <functional>
using namespace tiny_muduo;
using tiny_muduo::Version;
HttpServer::HttpServer(EventLoop* loop, const Address& address) : loop_(loop),
server_(loop, address) {
server_.SetConnectionCallback(
std::bind(&HttpServer::ConnectionCallback, this, _1));
server_.SetMessageCallback(
std::bind(&HttpServer::MessageCallback, this, _1, _2));
server_.SetThreadNums(kThreadNums);
SetHttpResponseCallback(std::bind(&HttpServer::HttpDefaultCallback, this, _1, _2));
}
HttpServer::~HttpServer() {
}
void HttpServer::MessageCallback(TcpConnection* connection,
Buffer* buffer) {
if (connection->IsShutdown()) return;
HttpContent* content = connection->GetHttpContent();
if (!content->ParseContent(buffer)) {
connection->Send("HTTP/1.1 400 Bad Request\r\n\r\n");
connection->Shutdown();
}
if (content->GetCompleteRequest()) {
DealWithRequest(content->request(), connection);
content->ResetContentState();
}
}
void HttpServer::DealWithRequest(const HttpRequest& request,
TcpConnection* connection) {
string connection_state = std::move(request.GetHeader("Connection"));
bool close = (connection_state == "Close" ||
(request.version() == kHttp10 &&
connection_state != "Keep-Alive"));
HttpResponse response(close);
response_callback_(request, response);
Buffer buffer;
response.AppendToBuffer(&buffer);
connection->Send(&buffer);
if (response.CloseConnection()) {
}
}
7、httpresponse.h(新添加)
#ifndef TINY_MUDUO_HTTPRESPONSE_H_
#define TINY_MUDUO_HTTPRESPONSE_H_
#include <string>
#include <utility>
#include "httprequest.h"
using std::string;
namespace tiny_muduo {
static const string CRLF = "\r\n";
enum HttpStatusCode {
k100Continue = 100,
k200OK = 200,
k400BadRequest = 400,
k403Forbidden = 403,
k404NotFound = 404,
k500InternalServerErrno = 500
};
class Buffer;
class HttpResponse {
public:
HttpResponse(bool close_connection) : type_("text/plain"),
close_connection_(close_connection) {
}
~HttpResponse() {}
void SetStatusCode(HttpStatusCode status_code) { status_code_ = status_code; }
void SetStatusMessage(const string& status_message) { status_message_ = std::move(status_message); }
void SetCloseConnection(bool close_connection) { close_connection_ = close_connection; }
void SetBodyType(const string& type) { type_ = type; }
void SetBodyType(const char* type) { type_ = type; }
void SetBody(const string& body) { body_ = body; }
void SetBody(const char* body) { body_ = std::move(string(body)); }
void AppendToBuffer(Buffer* buffer);
bool CloseConnection() { return close_connection_; }
private:
static const string server_name_;
static const string server_http_version_;
HttpStatusCode status_code_;
string status_message_;
string headers_;
string body_;
string type_;
bool close_connection_;
};
}
#endif
7、httpresponse.cc(新添加)
#include "httpresponse.h"
#include <string>
#include "buffer.h"
using namespace tiny_muduo;
using std::string;
const string HttpResponse::server_name_ = "Tiny_muduo";
const string HttpResponse::server_http_version_ = "HTTP/1.1";
void HttpResponse::AppendToBuffer(Buffer* buffer) {
string message;
message += (server_http_version_ + " " +
std::to_string(status_code_) + " " +
status_message_ + CRLF);
if (close_connection_) {
message += ("Connection: close" + CRLF);
} else {
message += ("Content-Length: ");
message += (std::__cxx11::to_string(body_.size()) + CRLF);
message += ("Connection: Keep-Alive" + CRLF);
message += ("Content-Type:" + type_ + CRLF);
message += ("Server: " + server_name_ + CRLF);
}
message += CRLF;
message += body_;
buffer->Append(message);
return;
}
8、httprequest.h(新添加)
#ifndef TINY_MUDUO_HTTPREQUEST_H_
#define TINY_MUDUO_HTTPREQUEST_H_
#include "httpparsestate.h"
#include <string>
#include <map>
using std::string;
namespace tiny_muduo {
static const char http[] = "HTTP/1.";
enum Method {
kGet,
kPost,
kPut,
kDelete,
kTrace,
kOptions,
kConnect,
kPatch
};
enum Version {
kHttp10,
kHttp11
};
class HttpRequest {
public:
HttpRequest();
~HttpRequest();
bool ParseRequestMethod(const char* start, const char* end);
void ParseRequestLine(const char* start, const char* end,
HttpRequestParseState& state);
void ParseHeaders(const char* start, const char* end,
HttpRequestParseState& state);
void ParseBody(const char* start, const char* end,
HttpRequestParseState& state);
Method method() const { return method_; }
const string& path() const { return path_; }
const string& query() const { return query_; }
Version version() const { return version_; }
const std::map<string, string>& headers() const { return headers_; }
string GetHeader(const string& header) const {
auto iter = headers_.find(header);
if (iter == headers_.end()) {
return string();
} else {
return iter->second;
}
}
private:
Method method_;
string path_;
string query_;
Version version_;
std::map<string, string> headers_;
};
}
#endif
8、httprequest.cc(新添加)
#include "httprequest.h"
#include <utility>
#include <algorithm>
#include "httpparsestate.h"
using namespace tiny_muduo;
using tiny_muduo::Method;
using tiny_muduo::HttpRequestParseState;
HttpRequest::HttpRequest() {
}
HttpRequest::~HttpRequest() {
}
bool HttpRequest::ParseRequestMethod(const char* start, const char* end) {
string method(start, end);
bool has_method = true;
if (method == "GET") {
method_ = kGet;
} else if (method == "POST") {
method_ = kPost;
} else if (method == "PUT") {
method_ = kPut;
} else if (method == "DELETE") {
method_ = kDelete;
} else if (method == "TRACE") {
method_ = kTrace;
} else if (method == "OPTIONS") {
method_ = kOptions;
} else if (method == "CONNECT") {
method_ = kConnect;
} else if (method == "PATCH") {
method_ = kPatch;
} else {
has_method = false;
}
return has_method;
}
void HttpRequest::ParseRequestLine(const char* start, const char* end,
HttpRequestParseState& state) {
{
const char* space = std::find(start, end, ' ');
if (space == end) {
state = kParseErrno;
return;
}
if (!ParseRequestMethod(start, space)) {
state = kParseErrno;
return;
}
start = space + 1;
}
{
const char* space = std::find(start, end, ' ');
if (space == end) {
state = kParseErrno;
return;
}
const char* query = std::find(start, end, '?');
if (query != end) {
path_ = std::move(string(start, query));
query_ = std::move(string(query + 1, space));
} else {
path_ = std::move(string(start, space));
}
start = space + 1;
}
{
const int httplen = sizeof(http) / sizeof(char) - 1;
const char* httpindex = std::search(start, end, http, http + httplen);
if (httpindex == end) {
state = kParseErrno;
return;
}
const char chr = *(httpindex + httplen);
if (httpindex + httplen + 1 == end && (chr == '1' || chr == '0')) {
if (chr == '1') {
version_ = kHttp11;
} else {
version_ = kHttp10;
}
} else {
state = kParseErrno;
return;
}
}
state = kParseHeaders;
}
void HttpRequest::ParseBody(const char* start, const char* end,
HttpRequestParseState& state) {
}
void HttpRequest::ParseHeaders(const char* start, const char* end,
HttpRequestParseState& state) {
if (start == end && *start == '\r' && *(start + 1) == '\n') {
state = kParseGotCompleteRequest;
return;
}
const char* colon = std::find(start, end, ':');
if (colon == end) {
state = kParseErrno;
return;
}
const char* vaild = colon + 1;
while (*(vaild++) != ' ') {}
headers_[std::move(string(start, colon))] = std::move(string(colon + 1, vaild));
return;
}
9、httpcontent.h(新添加)
#ifndef TINY_MUDUO_HTTPCONTENT_H_
#define TINY_MUDUO_HTTPCONTENT_H_
#include <utility>
#include <algorithm>
#include "buffer.h"
#include "httprequest.h"
#include "httpparsestate.h"
namespace tiny_muduo {
enum HttpRequestParseLine {
kLineOK,
kLineMore,
kLineErrno
};
class HttpContent {
public:
HttpContent();
~HttpContent();
void ParseLine(Buffer* buffer);
bool ParseContent(Buffer* buffer);
bool GetCompleteRequest() { return parse_state_ == kParseGotCompleteRequest; }
const HttpRequest& request() const { return request_; }
void ResetContentState() {
parse_state_ = kParseRequestLine;
line_state_ = kLineOK;
}
private:
int checked_index_;
HttpRequest request_;
HttpRequestParseLine line_state_;
HttpRequestParseState parse_state_;
};
}
#endif
9、httpcontent.cc(新添加)
#include "httpcontent.h"
#include "httprequest.h"
#include "httpparsestate.h"
using namespace tiny_muduo;
HttpContent::HttpContent() : checked_index_(0),
parse_state_(kParseRequestLine) {
}
HttpContent::~HttpContent() {}
void HttpContent::ParseLine(Buffer* buffer) {
line_state_ = kLineMore;
if (buffer->readablebytes() == 0) return;
int readable_index = buffer->readablebytes();
const char* buf = buffer->beginread();
for (; checked_index_ < readable_index; ++checked_index_) {
char chr = buf[checked_index_];
if (chr == '\n') {
if (checked_index_ && buf[checked_index_ - 1] == '\r') {
checked_index_ = checked_index_ + 1;
line_state_ = kLineOK;
} else {
line_state_ = kLineErrno;
}
return;
} else if (chr == '\r') {
if (checked_index_ == readable_index - 1) continue;
if (buf[checked_index_ + 1] == '\n') {
checked_index_ = checked_index_ + 2;
line_state_ = kLineOK;
} else {
line_state_ = kLineErrno;
}
return;
} else {
continue;
}
}
return;
}
bool HttpContent::ParseContent(Buffer* buffer) {
while (parse_state_ != kParseErrno) {
ParseLine(buffer);
if (line_state_ == kLineMore || line_state_ == kLineErrno) {
if (line_state_ == kLineErrno) {
parse_state_ = kParseErrno;
checked_index_ = 0;
}
break;
}
const char* start = buffer->beginread();
const char* end = start + (checked_index_ - 2);
if (parse_state_ == kParseRequestLine) {
request_.ParseRequestLine(start, end, parse_state_);
} else if (parse_state_ == kParseHeaders) {
request_.ParseHeaders(start, end, parse_state_);
} else if (parse_state_ == kParseBody) {
request_.ParseBody(start, end, parse_state_);
} else if (parse_state_ == kParseGotCompleteRequest) {
break;
}
buffer->RetrieveUntilIndex(start + checked_index_);
checked_index_ = 0;
}
return parse_state_ != kParseErrno;
}
3、其他组件(makefile等等)
1、httpstate.h(新添加)
#ifndef TINY_MUDUO_HTTPSTATE_H_
#define TINY_MUDUO_HTTPSTATE_H_
namespace tiny_muduo {
enum HttpRequestParseState {
kParseRequestLine,
kParseHeaders,
kParseBody,
kParseGotCompleteRequest,
kParseErrno,
};
}
#endif
2、httpresponsefile.h(新添加)
#ifndef TINY_MUDUO_HTTPRESPONSEFILE_H_
#define TINY_MUDUO_HTTPRESPONSEFILE_H_
namespace tiny_muduo {
const char favicon[555] = {
'\x89', 'P', 'N', 'G', '\xD', '\xA', '\x1A', '\xA',
'\x0', '\x0', '\x0', '\xD', 'I', 'H', 'D', 'R',
'\x0', '\x0', '\x0', '\x10', '\x0', '\x0', '\x0', '\x10',
'\x8', '\x6', '\x0', '\x0', '\x0', '\x1F', '\xF3', '\xFF',
'a', '\x0', '\x0', '\x0', '\x19', 't', 'E', 'X',
't', 'S', 'o', 'f', 't', 'w', 'a', 'r',
'e', '\x0', 'A', 'd', 'o', 'b', 'e', '\x20',
'I', 'm', 'a', 'g', 'e', 'R', 'e', 'a',
'd', 'y', 'q', '\xC9', 'e', '\x3C', '\x0', '\x0',
'\x1', '\xCD', 'I', 'D', 'A', 'T', 'x', '\xDA',
'\x94', '\x93', '9', 'H', '\x3', 'A', '\x14', '\x86',
'\xFF', '\x5D', 'b', '\xA7', '\x4', 'R', '\xC4', 'm',
'\x22', '\x1E', '\xA0', 'F', '\x24', '\x8', '\x16', '\x16',
'v', '\xA', '6', '\xBA', 'J', '\x9A', '\x80', '\x8',
'A', '\xB4', 'q', '\x85', 'X', '\x89', 'G', '\xB0',
'I', '\xA9', 'Q', '\x24', '\xCD', '\xA6', '\x8', '\xA4',
'H', 'c', '\x91', 'B', '\xB', '\xAF', 'V', '\xC1',
'F', '\xB4', '\x15', '\xCF', '\x22', 'X', '\x98', '\xB',
'T', 'H', '\x8A', 'd', '\x93', '\x8D', '\xFB', 'F',
'g', '\xC9', '\x1A', '\x14', '\x7D', '\xF0', 'f', 'v',
'f', '\xDF', '\x7C', '\xEF', '\xE7', 'g', 'F', '\xA8',
'\xD5', 'j', 'H', '\x24', '\x12', '\x2A', '\x0', '\x5',
'\xBF', 'G', '\xD4', '\xEF', '\xF7', '\x2F', '6', '\xEC',
'\x12', '\x20', '\x1E', '\x8F', '\xD7', '\xAA', '\xD5', '\xEA',
'\xAF', 'I', '5', 'F', '\xAA', 'T', '\x5F', '\x9F',
'\x22', 'A', '\x2A', '\x95', '\xA', '\x83', '\xE5', 'r',
'9', 'd', '\xB3', 'Y', '\x96', '\x99', 'L', '\x6',
'\xE9', 't', '\x9A', '\x25', '\x85', '\x2C', '\xCB', 'T',
'\xA7', '\xC4', 'b', '1', '\xB5', '\x5E', '\x0', '\x3',
'h', '\x9A', '\xC6', '\x16', '\x82', '\x20', 'X', 'R',
'\x14', 'E', '6', 'S', '\x94', '\xCB', 'e', 'x',
'\xBD', '\x5E', '\xAA', 'U', 'T', '\x23', 'L', '\xC0',
'\xE0', '\xE2', '\xC1', '\x8F', '\x0', '\x9E', '\xBC', '\x9',
'A', '\x7C', '\x3E', '\x1F', '\x83', 'D', '\x22', '\x11',
'\xD5', 'T', '\x40', '\x3F', '8', '\x80', 'w', '\xE5',
'3', '\x7', '\xB8', '\x5C', '\x2E', 'H', '\x92', '\x4',
'\x87', '\xC3', '\x81', '\x40', '\x20', '\x40', 'g', '\x98',
'\xE9', '6', '\x1A', '\xA6', 'g', '\x15', '\x4', '\xE3',
'\xD7', '\xC8', '\xBD', '\x15', '\xE1', 'i', '\xB7', 'C',
'\xAB', '\xEA', 'x', '\x2F', 'j', 'X', '\x92', '\xBB',
'\x18', '\x20', '\x9F', '\xCF', '3', '\xC3', '\xB8', '\xE9',
'N', '\xA7', '\xD3', 'l', 'J', '\x0', 'i', '6',
'\x7C', '\x8E', '\xE1', '\xFE', 'V', '\x84', '\xE7', '\x3C',
'\x9F', 'r', '\x2B', '\x3A', 'B', '\x7B', '7', 'f',
'w', '\xAE', '\x8E', '\xE', '\xF3', '\xBD', 'R', '\xA9',
'd', '\x2', 'B', '\xAF', '\x85', '2', 'f', 'F',
'\xBA', '\xC', '\xD9', '\x9F', '\x1D', '\x9A', 'l', '\x22',
'\xE6', '\xC7', '\x3A', '\x2C', '\x80', '\xEF', '\xC1', '\x15',
'\x90', '\x7', '\x93', '\xA2', '\x28', '\xA0', 'S', 'j',
'\xB1', '\xB8', '\xDF', '\x29', '5', 'C', '\xE', '\x3F',
'X', '\xFC', '\x98', '\xDA', 'y', 'j', 'P', '\x40',
'\x0', '\x87', '\xAE', '\x1B', '\x17', 'B', '\xB4', '\x3A',
'\x3F', '\xBE', 'y', '\xC7', '\xA', '\x26', '\xB6', '\xEE',
'\xD9', '\x9A', '\x60', '\x14', '\x93', '\xDB', '\x8F', '\xD',
'\xA', '\x2E', '\xE9', '\x23', '\x95', '\x29', 'X', '\x0',
'\x27', '\xEB', 'n', 'V', 'p', '\xBC', '\xD6', '\xCB',
'\xD6', 'G', '\xAB', '\x3D', 'l', '\x7D', '\xB8', '\xD2',
'\xDD', '\xA0', '\x60', '\x83', '\xBA', '\xEF', '\x5F', '\xA4',
'\xEA', '\xCC', '\x2', 'N', '\xAE', '\x5E', 'p', '\x1A',
'\xEC', '\xB3', '\x40', '9', '\xAC', '\xFE', '\xF2', '\x91',
'\x89', 'g', '\x91', '\x85', '\x21', '\xA8', '\x87', '\xB7',
'X', '\x7E', '\x7E', '\x85', '\xBB', '\xCD', 'N', 'N',
'b', 't', '\x40', '\xFA', '\x93', '\x89', '\xEC', '\x1E',
'\xEC', '\x86', '\x2', 'H', '\x26', '\x93', '\xD0', 'u',
'\x1D', '\x7F', '\x9', '2', '\x95', '\xBF', '\x1F', '\xDB',
'\xD7', 'c', '\x8A', '\x1A', '\xF7', '\x5C', '\xC1', '\xFF',
'\x22', 'J', '\xC3', '\x87', '\x0', '\x3', '\x0', 'K',
'\xBB', '\xF8', '\xD6', '\x2A', 'v', '\x98', 'I', '\x0',
'\x0', '\x0', '\x0', 'I', 'E', 'N', 'D', '\xAE',
'B', '\x60', '\x82',
};
const string love6_website = "<p align = \"middle\"><strong> <font color=\"#84C1FF\">Sharing And Geting. I'm Always Here</font> </strong> </p><hr />\
<p align = \"middle\"><strong> <font color=\"#84C1FF\">Love 6's Info</font> </strong> <br />\
<strong><font color=\"#AAAAFF\">Love 6's School: Hogwarts School </font></strong> <br />\
<strong><font color=\"#C1FFE4\">Love 6's Year In Univ: Sophomore </font></strong> <br />\
<strong><font color=\"#FFBFFF\">Love 6's Interests: Gaming Coding </font></strong> <br />\
<strong><font color=\"#A3D1D1\">Love 6's Occupation: Sorcerer </font></strong> <br /> \
<strong><font color=\"#A6FFA6\">Love 6's QQ Wechat: Personal Secret </font></strong> <br /> </p>\
<hr />\
<p align = \"middle\"><strong><font color=\"#84C1FF\"> Cat </font><br /> </strong> </p>\
<p align = \"middle\"><img src=\"https://img-blog.csdnimg.cn/6d28d9f8ad2b4c79be7a90a33e552caf.GIF\" alt=\"Cat\" width=\"200\" height=\"200\"></p>\
<hr />\
<p align = \"middle\"><strong><font color=\"#84C1FF\"> Love 6's Some Blogs - Keep Updating </font><br /> </strong></p></hr >\
<strong><font color=\"#AAAAFF\"> Touch Here -> </font></strong><a href=\"https://love6.blog.csdn.net/article/details/119133589\"> Operating system truth restore self-made operating system whole process records from scratch </a><br />\
<strong><font color=\"#FFBFFF\"> Touch Here -> </font></strong><a href=\"https://love6.blog.csdn.net/article/details/117517529\"> Harbin Institute of technology operating system lab full experiment blog link </a><br />\
<strong><font color=\"#C1FFE4\"> Touch Here -> </font></strong><a href=\"https://love6.blog.csdn.net/article/details/120071337\"> Computer network top-down lab full experiment blog link </a><br />\
<strong><font color=\"#A3D1D1\"> Touch Here -> </font></strong><a href=\"https://love6.blog.csdn.net/article/details/116152266\"> CSAPP Labs 1-6 Blog Link</a><hr />\
<p align = \"middle\"><strong><font color=\"#84C1FF\"> Do good deeds Don't ask future </font><br /> </strong></p>";
}
#endif
3、makefile(更新)
CC = g++
CFLAG = -Wall -c
OBJS = main.o httpserver.o httpresponse.o httpcontent.o httprequest.o\
tcpserver.o acceptor.o\
channel.o eventloop.o epoller.o tcpconnection.o\
eventloopthreadpool.o eventloopthread.o thread.o buffer.o\
$(TFLAG)
TFLAG = -lpthread
web_server : $(OBJS)
$(CC) $^ -o $@
main.o : main.cc eventloop.h address.h httpserver.h httprequest.h httpresponse.h\
httpresponsefile.h
$(CC) $(CFLAG) $< -o $@
httpserver.o : httpserver.cc httpserver.h buffer.h
$(CC) $(CFLAG) $< -o $@
httpresponse.o : httpresponse.cc httpresponse.h buffer.h
$(CC) $(CFLAG) $< -o $@
httpcontent.o : httpcontent.cc httpcontent.h httprequest.h httpparsestate.h
$(CC) $(CFLAG) $< -o $@
httprequest.o : httprequest.cc httprequest.h httpparsestate.h
$(CC) $(CFLAG) $< -o $@
tcpserver.o : tcpserver.cc tcpserver.h acceptor.h tcpconnection.h\
eventloopthreadpool.h
$(CC) $(CFLAG) $< -o $@
acceptor.o : acceptor.cc acceptor.h address.h channel.h
$(CC) $(CFLAG) $< -o $@
channel.o : channel.cc channel.h
$(CC) $(CFLAG) $< -o $@
eventloop.o : eventloop.cc eventloop.h channel.h mutex.h
$(CC) $(CFLAG) $< -o $@
eventloopthreadpool.o : eventloopthreadpool.cc eventloopthreadpool.h eventloopthread.h
$(CC) $(CFLAG) $< -o $@
eventloopthread.o : eventloopthread.cc eventloopthreadpool.h mutex.h\
condition.h eventloop.h
$(CC) $(CFLAG) $< -o $@
thread.o : thread.cc thread.h latch.h
$(CC) $(CFLAG) $< -o $@
epoller.o : epoller.cc epoller.h channel.h
$(CC) $(CFLAG) $< -o $@
tcpconnection.o : tcpconnection.cc tcpconnection.h \
channel.h buffer.h httpcontent.h
$(CC) $(CFLAG) $< -o $@
buffer.o : buffer.cc buffer.h
$(CC) $(CFLAG) $< -o $@
.PHONY : clean
clean:
rm *.o
4、http server 测试
这里就不考虑多并发的情况了 一直默认都是多线程 而且自己也都测试过的 也都是正常运行
多线程工作 之后再优化优化 毕竟里面我的event数组也没有进行额外的遇到注册满的情况 也没有去resize拓宽… 看看并行度的工作就留到后面 有自动化测试的时候 看看性能了 这里就先看看是否运行正确
1、火狐浏览器(正常路径访问)
2、火狐浏览器(/hello路径访问)
3、火狐浏览器(/favicon)
4、netcat 访问(正常、异常访问)
结束语
老样子 贴一张我现在linux的工作界面图 就当作结束吧 编辑文字到现在已经有35000字数了 网页已经很卡了
说实话 半个多月前走到现在 真的还是特别开心的 真的还是通过博客一步步见证自己在网络编程上面 从零到有 也就像博客网页标题一样 从零开始 因为真的是从零开始 编辑到现在已经11点了 我也要差不多回寝室了
就这样开开心心的 结束这篇博客吧~
|