文章目录
- 全流程实现博客链接
- 前引
- (九)--- 目前总览代码如下 得继续脚步前行
- 1、主要核心部分代码
- 1、main.cc
- 2、httpserver.h
- 2、httpserver.cc
- 3、tcpserver.h
- 3、tcpserver.cc
- 4、acceptor.h
- 4、acceptor.cc
- 5、eventloop.h
- 5、eventloop.cc
- 6、epoller.h
- 6、epoller.cc
- 7、channel.h
- 7、channel.cc
- 8、tcpconnection.h
- 8、tcpconnection.cc
- 9、buffer.h
- 9、buffer.cc
- 10、thread.h
- 10、thread.cc
- 11、eventloopthread.h
- 11、eventloopthread.cc
- 12、eventloopthreadpool.h
- 12、eventloopthreadpool.cc
- 2、httpserver相关文件
- 3、其他组件(mutex makefile等)
- 结束语
全流程实现博客链接
从零开始自制实现C++ High-Performance WebServer 全流程记录(基于muduo网络库)
前引
目前性能还是有一些差距 我初步揣测
是不是由于我httpserver
的分析函数 是完全按照我的思路写的
但是比muduo库更为复杂 处理就更细致一点 而且也引入了多个参数…
我觉得是这个原因
主要是性能差距也没有那么大… 而且确实
我是先判断是否存在一行 对每个字符判断
个人觉得判断函数写的也不是那么好 用std::search
应该感觉效果好一些
但是主要 我觉得这个地方 状态机 用一个checked_index
判断过的字符就可以不用判断了 但是其实 如果用webbench
来判断的话 其实这个过程肯定是没有必要的… 因为发送的情况不会出现的 每次只发送一两个字节的情况
后面再改改 看看性能会不会提升到和muduo
库持平 之后大概率要改用ET
工作模式
现在性能差距相比之前已经相对来说很小了 下面给张截图吧
明天再来改改了
(九)— 目前总览代码如下 得继续脚步前行
当然代码还在持续迭代
之后可能还要重构一下http分析函数 让他更简单一点
1、主要核心部分代码
1、main.cc
#include <stdio.h>
#include <iostream>
#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.ico" || path == "/favicon") {
response.SetStatusCode(k200OK);
response.SetBodyType("image/png");
response.SetBody(string(favicon, sizeof(favicon)));
} else {
response.SetStatusCode(k404NotFound);
response.SetStatusMessage("Not Found");
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、httpserver.h
#ifndef TINY_MUDUO_HTTPSERVER_H_
#define TINY_MUDUO_HTTPSERVER_H_
#include <stdio.h>
#include <functional>
#include <utility>
#include "callback.h"
#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 = 6;
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(const TcpConnectionPtr& connection) {
}
void MessageCallback(const TcpConnectionPtr& connection, Buffer* buffer);
void SetHttpResponseCallback(HttpResponseCallback response_callback) {
response_callback_ = std::move(response_callback);
}
void DealWithRequest(const HttpRequest& request, const TcpConnectionPtr& connection);
private:
EventLoop* loop_;
TcpServer server_;
HttpResponseCallback response_callback_;
};
}
#endif
2、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(const TcpConnectionPtr& connection,
Buffer* buffer) {
HttpContent* content = connection->GetHttpContent();
if (connection->IsShutdown()) return;
if (!content->ParseContent(buffer)) {
connection->Send("HTTP/1.1 400 Bad Request\r\n\r\n");
connection->Shutdown();
return;
}
if (content->GetCompleteRequest()) {
DealWithRequest(content->request(), connection);
content->ResetContentState();
}
}
void HttpServer::DealWithRequest(const HttpRequest& request,
const TcpConnectionPtr& 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()) {
connection->Shutdown();
}
}
3、tcpserver.h
#ifndef TINY_MUDUO_TCPSERVER_H_
#define TINY_MUDUO_TCPSERVER_H_
#include <memory>
#include <unordered_map>
#include "callback.h"
#include "eventloop.h"
#include "acceptor.h"
#include "eventloopthreadpool.h"
#include "tcpconnection.h"
namespace tiny_muduo {
class Address;
class TcpServer {
public:
TcpServer(EventLoop* loop, const Address& address);
~TcpServer();
void Start() {
threads_->StartLoop();
loop_->RunOneFunc(std::bind(&Acceptor::Listen, acceptor_.get()));
}
void SetConnectionCallback(const ConnectionCallback& callback) {
connection_callback_ = callback;
}
void SetMessageCallback(const MessageCallback& callback) {
message_callback_ = callback;
}
void SetThreadNums(int thread_nums) {
threads_->SetThreadNums(thread_nums);
}
void HandleClose(const TcpConnectionPtr& conn);
void HandleCloseInLoop(const TcpConnectionPtr& ptr);
void HandleNewConnection(int connfd);
private:
typedef std::unordered_map<int, TcpconnectionPtr> ConnectionMap;
EventLoop* loop_;
std::unique_ptr<EventLoopThreadPool> threads_;
std::unique_ptr<Acceptor> acceptor_;
ConnectionCallback connection_callback_;
MessageCallback message_callback_;
ConnectionMap connections_;
};
}// namespace tiny_muduo
#endif
3、tcpserver.cc
#include "tcpserver.h"
#define NDEBUG
#include <assert.h>
#include <utility>
#include "eventloopthreadpool.h"
#include "acceptor.h"
#include "tcpconnection.h"
using namespace tiny_muduo;
TcpServer::TcpServer(EventLoop* loop, const Address& address)
: loop_(loop),
threads_(new EventLoopThreadPool(loop_)),
acceptor_(new Acceptor(loop_, address)) {
acceptor_->SetNewConnectionCallback(std::bind(&TcpServer::HandleNewConnection, this, _1));
}
TcpServer::~TcpServer() {
for (auto& pair : connections_) {
TcpConnectionPtr ptr(pair.second);
pair.second.reset();
ptr->loop()->RunOneFunc(std::bind(&TcpConnection::ConnectionDestructor, ptr));
}
}
void TcpServer::HandleClose(const TcpConnectionPtr& ptr) {
loop_->QueueOneFunc(std::bind(&TcpServer::HandleCloseInLoop, this, ptr));
}
void TcpServer::HandleCloseInLoop(const TcpConnectionPtr& ptr) {
assert(connections_.find(ptr->fd()) != connections_.end());
connections_.erase(connections_.find(ptr->fd()));
EventLoop* loop = ptr->loop();
loop->QueueOneFunc(std::bind(&TcpConnection::ConnectionDestructor, ptr));
}
void TcpServer::HandleNewConnection(int connfd) {
EventLoop* loop = threads_->NextLoop();
TcpConnectionPtr ptr(new TcpConnection(loop, connfd));
connections_[connfd] = ptr;
ptr->SetConnectionCallback(connection_callback_);
ptr->SetMessageCallback(message_callback_);
ptr->SetCloseCallback(std::bind(&TcpServer::HandleClose, this, _1));
loop->RunOneFunc(std::bind(&TcpConnection::ConnectionEstablished, ptr));
}
4、acceptor.h
#ifndef TINY_MUDUO_ACCEPTOR_H_
#define TINY_MUDUO_ACCEPTOR_H_
#include <memory>
#include <functional>
namespace tiny_muduo {
class EventLoop;
class Address;
class Channel;
class Acceptor {
public:
typedef std::function<void (int)> NewConnectionCallback;
Acceptor(EventLoop* loop, const Address& address);
~Acceptor();
void SetNonBlocking(int fd); // for accept non-blocking not for accept4
void BindListenFd(const Address& address);
void Listen();
void NewConnection();
void SetNewConnectionCallback(const NewConnectionCallback& callback) {
new_connection_callback_ = std::move(callback);
}
private:
EventLoop* loop_;
int listenfd_;
std::unique_ptr<Channel> channel_;
NewConnectionCallback new_connection_callback_;
};
}
#endif
4、acceptor.cc
#include "acceptor.h"
#include <assert.h>
#include <cstring>
#include <sys/socket.h>
#include <sys/types.h>
#include <bits/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <functional>
#include "address.h"
#include "channel.h"
using namespace tiny_muduo;
Acceptor::Acceptor(EventLoop* loop, const Address& address)
: loop_(loop),
listenfd_(::socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP)),
channel_(new Channel(loop, listenfd_)) {
int option_val = 1;
::setsockopt(listenfd_, SOL_SOCKET, SO_KEEPALIVE,
&option_val, static_cast<socklen_t>(sizeof option_val));
BindListenFd(address);
channel_->SetReadCallback(std::bind(&Acceptor::NewConnection, this));
}
Acceptor::~Acceptor() {
channel_->DisableAll();
loop_->Remove(channel_.get());
::close(listenfd_);
}
void Acceptor::SetNonBlocking(int fd) {
int old_state = fcntl(fd, F_GETFL);
int new_state = old_state | O_NONBLOCK;
fcntl(fd, F_SETFL, new_state);
(void)new_state;
}
void Acceptor::BindListenFd(const Address& addr) {
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(addr.port());
inet_pton(AF_INET, addr.ip(), &address.sin_addr);
int ret = bind(listenfd_, (struct sockaddr*)(&address), sizeof(address));
assert(ret != -1);
}
void Acceptor::Listen() {
int ret = listen(listenfd_, SOMAXCONN);
assert(ret != -1);
channel_->EnableReading();
}
void Acceptor::NewConnection() {
struct sockaddr_in client;
socklen_t client_addrlength = sizeof(client);
int connfd = ::accept4(listenfd_, (struct sockaddr*)&client, &client_addrlength, SOCK_NONBLOCK | SOCK_CLOEXEC);
int option_val = 1;
::setsockopt(listenfd_, SOL_SOCKET, SO_KEEPALIVE,
&option_val, static_cast<socklen_t>(sizeof option_val));
assert(connfd > 0);
new_connection_callback_(connfd);
}
5、eventloop.h
#ifndef TINY_MUDUO_EVENTLOOP_H_
#define TINY_MUDUO_EVENTLOOP_H_
#include <stdint.h>
#include <unistd.h>
#include <sys/eventfd.h>
#include <pthread.h>
#include <vector>
#include <functional>
#include <memory>
#include "mutex.h"
#include "epoller.h"
namespace tiny_muduo {
class Epoller;
class Channel;
class EventLoop {
public:
typedef std::vector<Channel*> Channels;
typedef std::function<void()> BasicFunc;
typedef std::vector<BasicFunc> ToDoList;
EventLoop();
~EventLoop();
bool IsInThreadLoop() { return ::pthread_self() == tid_; }
void Update(Channel* channel) { epoller_->Update(channel); }
void Remove(Channel* channel) { epoller_->Remove(channel); }
void Loop();
void HandleRead();
void QueueOneFunc(BasicFunc func);
void RunOneFunc(BasicFunc func);
void DoToDoList();
private:
pthread_t tid_;
std::unique_ptr<Epoller> epoller_;
int wakeup_fd_;
std::unique_ptr<Channel> wakeup_channel_;
bool calling_functors_;
Channels active_channels_;
ToDoList to_do_list_;
MutexLock mutex_;
};
} // namespace tiny_muduo
#endif
5、eventloop.cc
#include "eventloop.h"
#include <unistd.h>
#include <sys/eventfd.h>
#include <pthread.h>
#include <utility>
#include "mutex.h"
#include "channel.h"
using namespace tiny_muduo;
EventLoop::EventLoop()
: tid_(::pthread_self()),
epoller_(new Epoller()),
wakeup_fd_(::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)),
wakeup_channel_(new Channel(this, wakeup_fd_)),
calling_functors_(false) {
wakeup_channel_->SetReadCallback(std::bind(&EventLoop::HandleRead, this));
wakeup_channel_->EnableReading();
}
EventLoop::~EventLoop() {
wakeup_channel_->DisableAll();
Remove(wakeup_channel_.get());
}
void EventLoop::Loop() {
while (1) {
active_channels_.clear();
epoller_->Poll(active_channels_);
for (const auto& channel : active_channels_) {
channel->HandleEvent();
}
DoToDoList();
}
}
void EventLoop::HandleRead() {
uint64_t read_one_byte = 1;
::read(wakeup_fd_, &read_one_byte, sizeof(read_one_byte));
return;
}
void EventLoop::QueueOneFunc(BasicFunc func) {
{
MutexLockGuard lock(mutex_);
to_do_list_.emplace_back(std::move(func));
}
if (!IsInThreadLoop() || calling_functors_) {
uint64_t write_one_byte = 1;
::write(wakeup_fd_, &write_one_byte, sizeof(write_one_byte));
}
}
void EventLoop::RunOneFunc(BasicFunc func) {
if (IsInThreadLoop()) {
func();
} else {
QueueOneFunc(std::move(func));
}
}
void EventLoop::DoToDoList() {
ToDoList functors;
calling_functors_ = true;
{
MutexLockGuard lock(mutex_);
functors.swap(to_do_list_);
}
for (const auto& func : functors) {
func();
}
calling_functors_ = false;
}
6、epoller.h
#ifndef TINY_MUDUO_EPOLLER_H_
#define TINY_MUDUO_EPOLLER_H_
#include <sys/epoll.h>
#include <vector>
#include <unordered_map>
namespace {
const int kDefaultEvents = 16;
}
namespace tiny_muduo {
class Channel;
class Epoller {
public:
typedef std::vector<epoll_event> Events;
typedef std::vector<Channel*> Channels;
Epoller();
~Epoller();
void Remove(Channel* channel_);
void Poll(Channels& channels);
int EpollWait() { return epoll_wait(epollfd_, &*events_.begin(), static_cast<int>(events_.size()), -1); }
void FillActiveChannels(int eventnums, Channels& channels);
void Update(Channel* channel);
void UpdateChannel(int operation, Channel* channel);
private:
typedef std::unordered_map<int, Channel*> ChannelMap;
int epollfd_;
Events events_;
ChannelMap channels_;
};
}
#endif
6、epoller.cc
#include "epoller.h"
#define NDEBUG
#include <assert.h>
#include <string.h>
#include <sys/epoll.h>
#include <vector>
#include "channel.h"
using namespace tiny_muduo;
Epoller::Epoller()
: epollfd_(::epoll_create1(EPOLL_CLOEXEC)),
events_(kDefaultEvents),
channels_() {
}
Epoller::~Epoller() {
::close(epollfd_);
}
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);
}
if (eventnums == static_cast<int>(events_.size())) {
events_.resize(eventnums * 2);
}
}
void Epoller::Remove(Channel* channel) {
int fd = channel->fd();
ChannelState state = channel->state();
assert(state == kDeleted || state == kAdded);
if (state == kAdded) {
UpdateChannel(EPOLL_CTL_DEL, channel);
}
channel->SetChannelState(kNew);
channels_.erase(fd);
return;
}
void Epoller::Update(Channel* channel) {
int op = 0, events = channel->events();
ChannelState state = channel->state();
int fd = channel->fd();
if (state == kNew || state == kDeleted) {
if (state == kNew) {
assert(channels_.find(fd) == channels_.end());
channels_[fd] = channel;
} else {
assert(channels_.find(fd) != channels_.end());
assert(channels_[fd] == channel);
}
op = EPOLL_CTL_ADD;
channel->SetChannelState(kAdded);
} else {
assert(channels_.find(fd) != channels_.end());
assert(channels_[fd] == channel);
if (events == 0) {
op = EPOLL_CTL_DEL;
channel->SetChannelState(kDeleted);
} else {
op = EPOLL_CTL_MOD;
}
}
UpdateChannel(op, channel);
}
void Epoller::UpdateChannel(int operation, Channel* channel) {
struct epoll_event event;
memset(&event, '\0', sizeof(event));
event.events = channel->events();
event.data.ptr = static_cast<void*>(channel);
epoll_ctl(epollfd_, operation, channel->fd(), &event);
return;
}
7、channel.h
#ifndef TINY_MUDUO_CHANNEL_H_
#define TINY_MUDUO_CHANNEL_H_
#include <sys/epoll.h>
#include <utility>
#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(ReadCallback callback) {
read_callback_ = std::move(callback);
}
void SetWriteCallback(WriteCallback callback) {
write_callback_ = std::move(callback);
}
void EnableReading() {
events_ |= (EPOLLIN | EPOLLPRI);
Update();
}
void EnableWriting() {
events_ |= EPOLLOUT;
Update();
}
void DisableAll() {
events_ = 0;
Update();
}
void DisableWriting() {
events_ &= ~EPOLLOUT;
Update();
}
void Update() {
loop_->Update(this);
}
void SetReceivedEvents(int events) {
recv_events_ = events;
}
void SetChannelState(ChannelState state) {
state_ = state;
}
int fd() const { return fd_; }
int events() const { return events_; }
int recv_events() const { return recv_events_; }
ChannelState state() const { return state_; }
bool IsWriting() { return events_ & EPOLLOUT; }
bool IsReading() { return events_ & (EPOLLIN | EPOLLPRI); }
private:
EventLoop* loop_;
int fd_;
int events_; // update events
int recv_events_; // epoll received events
ChannelState state_;
ReadCallback read_callback_;
WriteCallback write_callback_;
};
}
#endif
7、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),
state_(kNew) {
}
Channel::~Channel() {
}
void Channel::HandleEvent() {
if (recv_events_ & (EPOLLIN | EPOLLPRI | EPOLLRDHUP)) {
if(read_callback_) {
read_callback_();
}
}
if (recv_events_ & EPOLLOUT) {
if(write_callback_) {
write_callback_();
}
}
}
8、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 <memory>
#include <utility>
#include "callback.h"
#include "channel.h"
#include "buffer.h"
#include "httpcontent.h"
using std::string;
namespace tiny_muduo {
class EventLoop;
class TcpConnection : public std::enable_shared_from_this<TcpConnection> {
public:
enum ConnectionState {
kConnected,
kDisconnected
};
TcpConnection(EventLoop* loop,int connfd);
~TcpConnection();
void SetConnectionCallback(ConnectionCallback callback) {
connection_callback_ = std::move(callback);
}
void SetMessageCallback(MessageCallback callback) {
message_callback_ = std::move(callback);
}
void SetCloseCallback(CloseCallback callback) {
close_callback_ = std::move(callback);
}
void ConnectionEstablished() {
state_ = kConnected;
channel_->EnableReading();
connection_callback_(shared_from_this(), &input_buffer_);
}
HttpContent* GetHttpContent() {
return &content_;
}
void Shutdown();
bool IsShutdown() { return shutdown_state_; }
void ConnectionDestructor();
void HandleClose();
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)); }
int fd() const { return fd_; }
EventLoop* loop() const { return loop_; }
private:
EventLoop* loop_;
int fd_;
ConnectionState state_;
std::unique_ptr<Channel> channel_;
Buffer input_buffer_;
Buffer output_buffer_;
HttpContent content_;
bool shutdown_state_;
ConnectionCallback connection_callback_;
MessageCallback message_callback_;
CloseCallback close_callback_;
};
typedef std::shared_ptr<TcpConnection> TcpconnectionPtr;
} // namespace tiny_muduo
#endif
8、tcpconnection.cc
#include "tcpconnection.h"
// #define NDEBUG
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "channel.h"
#include "buffer.h"
using namespace tiny_muduo;
TcpConnection::TcpConnection(EventLoop* loop, int connfd)
: loop_(loop),
fd_(connfd),
state_(kDisconnected),
channel_(new Channel(loop_, fd_)),
shutdown_state_(false) {
channel_->SetReadCallback(std::bind(&TcpConnection::HandleMessage, this));
channel_->SetWriteCallback(std::bind(&TcpConnection::HandleWrite, this));
}
TcpConnection::~TcpConnection() {
//printf("TcpConnection::~TcpConnection destructor\n");
::close(fd_);
}
void TcpConnection::ConnectionDestructor() {
if (state_ == kConnected) {
state_ = kDisconnected;
channel_->DisableAll();
}
loop_->Remove(channel_.get());
}
void TcpConnection::HandleClose() {
state_ = kDisconnected;
channel_->DisableAll();
TcpConnectionPtr guard(shared_from_this());
close_callback_(guard);
}
void TcpConnection::HandleMessage() {
int read_size = input_buffer_.ReadFd(fd_);
if (read_size > 0) {
message_callback_(shared_from_this(), &input_buffer_);
} else if (read_size == 0) {
HandleClose();
}
}
void TcpConnection::HandleWrite() {
int len = output_buffer_.readablebytes();
int remaining = len;
int send_size = ::write(fd_, output_buffer_.Peek(), remaining);
remaining -= send_size;
output_buffer_.Retrieve(send_size);
assert(remaining <= len);
if (!output_buffer_.readablebytes()) {
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 = ::write(fd_, message, len);
remaining -= send_size;
}
assert(remaining <= len);
if (remaining > 0) {
output_buffer_.Append(message + send_size, remaining);
if (!channel_->IsWriting()) {
channel_->EnableWriting();
}
}
}
void TcpConnection::Shutdown() {
if (!channel_->IsWriting()) {
::shutdown(fd_, SHUT_WR);
shutdown_state_ = true;
}
}
void TcpConnection::Send(Buffer* buffer) {
Send(buffer->Peek(), buffer->readablebytes());
buffer->RetrieveAll();
}
void TcpConnection::Send(const string& message) {
Send(message.data(), message.size());
}
9、buffer.h
#ifndef TINY_MUDUO_BUFFER_H_
#define TINY_MUDUO_BUFFER_H_
#include <vector>
#include <algorithm>
#include <string>
#define NDEBUG
#include <assert.h>
#include <cstring>
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) {
Append(message, strlen(message));
}
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) {
assert(readablebytes() >= 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_ = kPrePendIndex + readablebytes();
read_index_ = kPrePendIndex;
} else {
buffer_.resize(buffer_.capacity() + len);
}
}
private:
std::vector<char> buffer_;
int read_index_;
int write_index_;
};
}
#endif
9、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) {
printf("Buffer::ReadFd readn < 0 SYS_ERR\n");
}
else if (readn <= writable) {
write_index_ += readn;
} else {
write_index_ = buffer_.size();
Append(extrabuf, readn - writable);
}
return readn;
}
10、thread.h
#ifndef TINY_MUDUO_THREAD_H_
#define TINY_MUDUO_THREAD_H_
#include <pthread.h>
#include <functional>
#include "latch.h"
namespace tiny_muduo {
class Thread {
public:
typedef std::function<void ()> ThreadFunc;
Thread(const ThreadFunc& func);
~Thread();
void StartThread();
private:
pthread_t pthread_id_;
ThreadFunc func_;
Latch latch_;
};
struct ThreadData {
typedef tiny_muduo::Thread::ThreadFunc ThreadFunc;
ThreadFunc func_;
Latch* latch_;
ThreadData(ThreadFunc& func, Latch* latch)
: func_(func),
latch_(latch) {
}
void RunOneFunc() {
latch_->CountDown();
latch_ = nullptr;
func_();
}
};
}
#endif
10、thread.cc
#include "thread.h"
#include <pthread.h>
#include "latch.h"
using namespace tiny_muduo;
static void* ThreadRun(void* arg) {
ThreadData* ptr = static_cast<ThreadData*>(arg);
ptr->RunOneFunc();
delete ptr;
return nullptr;
}
Thread::Thread(const ThreadFunc& func)
: pthread_id_(-1),
func_(func),
latch_(1) {
}
Thread::~Thread() {
::pthread_detach(pthread_id_);
}
void Thread::StartThread() {
ThreadData* ptr = new ThreadData(func_, &latch_);
::pthread_create(&pthread_id_, nullptr, ThreadRun, ptr);
latch_.Wait();
}
11、eventloopthread.h
#ifndef TINY_MUDUO_EVENTLOOPTHREAD_H
#define TINY_MUDUO_EVENTLOOPTHREAD_H
#include "thread.h"
#include "mutex.h"
#include "condition.h"
namespace tiny_muduo {
class EventLoop;
class EventLoopThread {
public:
EventLoopThread();
~EventLoopThread();
void StartFunc();
EventLoop* StartLoop();
private:
EventLoop* loop_;
Thread thread_;
MutexLock mutex_;
Condition cond_;
};
}
#endif
11、eventloopthread.cc
#include "eventloopthread.h"
#include <pthread.h>
#include <functional>
#include "mutex.h"
#include "condition.h"
#include "eventloop.h"
using namespace tiny_muduo;
EventLoopThread::EventLoopThread()
: loop_(nullptr),
thread_(std::bind(&EventLoopThread::StartFunc, this)),
mutex_(),
cond_(mutex_) {
}
EventLoopThread::~EventLoopThread() {}
EventLoop* EventLoopThread::StartLoop() {
thread_.StartThread();
EventLoop* loop = nullptr;
{
MutexLockGuard lock(mutex_);
while (loop_ == nullptr) {
cond_.Wait();
}
loop = loop_;
}
return loop;
}
void EventLoopThread::StartFunc() {
EventLoop loop;
{
MutexLockGuard lock(mutex_);
loop_ = &loop;
cond_.Signal();
}
loop_->Loop();
{
MutexLockGuard lock(mutex_);
loop_ = nullptr;
}
}
12、eventloopthreadpool.h
#ifndef TINY_MUDUO_EVENTLOOPTHREADPOOL_H_
#define TINY_MUDUO_EVENTLOOPTHREADPOOL_H_
#include <vector>
#include <memory>
namespace tiny_muduo {
class EventLoopThread;
class EventLoop;
class EventLoopThreadPool {
public:
typedef std::vector<std::unique_ptr<EventLoopThread>> Thread;
typedef std::vector<EventLoop*> Loop;
EventLoopThreadPool(EventLoop* loop);
~EventLoopThreadPool();
void SetThreadNums(int thread_nums) {
thread_nums_ = thread_nums;
}
void StartLoop();
EventLoop* NextLoop();
private:
EventLoop* base_loop_;
Thread threads_;
Loop loops_;
int thread_nums_;
int next_;
};
}
#endif
12、eventloopthreadpool.cc
#include "eventloopthreadpool.h"
#include <memory>
#include "eventloopthread.h"
using namespace tiny_muduo;
EventLoopThreadPool::EventLoopThreadPool(EventLoop* loop)
: base_loop_(loop),
threads_(),
loops_(),
thread_nums_(0),
next_(0) {
}
EventLoopThreadPool::~EventLoopThreadPool() {}
void EventLoopThreadPool::StartLoop() {
for (int i = 0; i < thread_nums_; ++i) {
EventLoopThread* ptr = new EventLoopThread();
threads_.emplace_back(std::unique_ptr<EventLoopThread>(ptr));
loops_.emplace_back(ptr->StartLoop());
}
}
EventLoop* EventLoopThreadPool::NextLoop() {
EventLoop* ret = base_loop_;
if (!loops_.empty()) {
ret = loops_[next_];
next_ = (next_ + 1) % thread_nums_;
}
return ret;
}
2、httpserver相关文件
1、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
1、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 != '\r' && chr != '\n') continue;
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 {
if (checked_index_ && buf[checked_index_ - 1] == '\r') {
checked_index_ = checked_index_ + 1;
line_state_ = kLineOK;
} else {
line_state_ = kLineErrno;
}
return;
}
}
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;
}
2、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
2、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;
}
3、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_;
HttpStatusCode status_code_;
string status_message_;
string headers_;
string body_;
string type_;
bool close_connection_;
};
}
#endif
3、httpresponse.cc
#include "httpresponse.h"
#include <stdio.h>
#include <string>
#include "buffer.h"
using namespace tiny_muduo;
using std::string;
const string HttpResponse::server_name_ = "Tiny_muduo";
void HttpResponse::AppendToBuffer(Buffer* buffer) {
char buf[32] = {0};
snprintf(buf, sizeof(buf), "HTTP/1.1 %d ",status_code_);
buffer->Append(buf);
buffer->Append(status_message_);
buffer->Append(CRLF);
if (close_connection_) {
buffer->Append("Connection: close\r\n");
} else {
snprintf(buf, sizeof(buf), "Content-Length: %zd\r\n", body_.size()); // no need to memset this is longer than HTTP... one
buffer->Append(buf);
buffer->Append("Connection: Keep-Alive\r\n");
}
buffer->Append("Content-Type: ");
buffer->Append(type_);
buffer->Append(CRLF);
buffer->Append("Server: ");
buffer->Append(server_name_);
buffer->Append(CRLF);
buffer->Append(CRLF);
buffer->Append(body_);
return;
}
4、httpparsestate.h
#ifndef TINY_MUDUO_HTTPSTATE_H_
#define TINY_MUDUO_HTTPSTATE_H_
namespace tiny_muduo {
enum HttpRequestParseState {
kParseRequestLine,
kParseHeaders,
kParseBody,
kParseGotCompleteRequest,
kParseErrno,
};
}
#endif
3、其他组件(mutex makefile等)
1、mutex
#ifndef TINY_MUDUO_MUTEX_H_
#define TINY_MUDUO_MUTEX_H_
#include "pthread.h"
namespace tiny_muduo {
class MutexLock {
public:
MutexLock() {
pthread_mutex_init(&mutex_, nullptr);
}
~MutexLock() {
pthread_mutex_destroy(&mutex_);
}
bool Lock() {
return pthread_mutex_lock(&mutex_) == 0;
}
bool Unlock() {
return pthread_mutex_unlock(&mutex_) == 0;
}
pthread_mutex_t* mutex() { return &mutex_; }
private:
pthread_mutex_t mutex_;
};
class MutexLockGuard {
public:
MutexLockGuard(MutexLock& mutex) : mutex_(mutex) {
mutex_.Lock();
}
~MutexLockGuard() {
mutex_.Unlock();
}
private:
MutexLock& mutex_;
};
}
#endif
2、condition.h
#ifndef TINY_MUDUO_CONDITION_H_
#define TINY_MUDUO_CONDITION_H_
#include "pthread.h"
#include "mutex.h"
namespace tiny_muduo {
class Condition {
public:
Condition(MutexLock& mutex) : mutex_(mutex) {
pthread_cond_init(&cond_, nullptr);
}
~Condition() {
pthread_cond_destroy(&cond_);
}
bool Wait() {
int ret = 0;
ret = pthread_cond_wait(&cond_, mutex_.mutex());
return ret == 0;
}
bool Signal() {
return pthread_cond_signal(&cond_);
}
bool BroadCast() {
return pthread_cond_broadcast(&cond_);
}
private:
MutexLock& mutex_;
pthread_cond_t cond_;
};
}
#endif
3、latch.h
#ifndef TINY_MUDUO_LATCH_H_
#define TINY_MUDUO_LATCH_H_
#include "mutex.h"
#include "condition.h"
namespace tiny_muduo {
class Latch {
public:
Latch(int count) : count_(count), mutex_(), cond_(mutex_) {}
void CountDown() {
MutexLockGuard lock(mutex_);
--count_;
if (count_ == 0) {
cond_.BroadCast();
}
}
void Wait() {
MutexLockGuard lock(mutex_);
while (count_ > 0) {
cond_.Wait();
}
}
private:
int count_;
MutexLock mutex_;
Condition cond_;
};
}
#endif
4、callback.h
#ifndef TINY_MUDUO_CALLBACK_H_
#define TINY_MUDUO_CALLBACK_H_
#include <memory>
#include <functional>
using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;
namespace tiny_muduo {
class TcpConnection;
typedef std::shared_ptr<TcpConnection> TcpConnectionPtr;
class Buffer;
typedef std::function<void (const TcpConnectionPtr&, Buffer*)> ConnectionCallback;
typedef std::function<void (const TcpConnectionPtr&, Buffer*)> MessageCallback;
typedef std::function<void ()> ReadCallback;
typedef std::function<void ()> WriteCallback;
typedef std::function<void (const TcpConnectionPtr&)> CloseCallback;
}
#endif
5、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
webserver : $(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
结束语
哎 路还有很长的路要走 IO库 定时器
可能还要重构HTTPserver的逻辑处理 后面还要可能修改epoll的工作状态
但是毕竟走到现在了 还是得坚持下去 之后再回头看看这里 可能也觉得别有一番感觉 哈哈
各位下一篇见了~