- 前引
- (九)--- 目前总览代码如下 得继续脚步前行
- 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相关文件
- 1、httpcontent.h
- 1、httpcontent.cc
- 2、httprequest.h
- 2、httprequest.cc
- 3、httpresponse.h
- 3、httpresponse.cc
- 4、httpparsestate.h
- 3、其他组件(mutex makefile等)
- 1、mutex
- 2、condition.h
- 3、latch.h
- 4、callback.h
- 5、makefile
- 结束语
前引
目前性能还是有一些差距 我初步揣测
是不是由于我httpserver
的分析函数 是完全按照我的思路写的
但是比muduo库更为复杂 处理就更细致一点 而且也引入了多个参数…
我觉得是这个原因
主要是性能差距也没有那么大… 而且确实
我是先判断是否存在一行 对每个字符判断
个人觉得判断函数写的也不是那么好 用std::search
应该感觉效果好一些
但是主要 我觉得这个地方 状态机 用一个checked_index
判断过的字符就可以不用判断了 但是其实 如果用webbench
来判断的话 其实这个过程肯定是没有必要的… 因为发送的情况不会出现的 每次只发送一两个字节的情况
后面再改改 看看性能会不会提升到和muduo
库持平 之后大概率要改用ET
工作模式
现在性能差距相比之前已经相对来说很小了 下面给张截图吧
明天再来改改了
(九)— 目前总览代码如下 得继续脚步前行
当然代码还在持续迭代
之后可能还要重构一下http分析函数 让他更简单一点
1、主要核心部分代码
1、main.cc
#include
#include
#include
#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
#include
#include
#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
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
#include
#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
#include
#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
#include
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
#include
#include
#include
#include
#include
#include
#include
#include
#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
#include
#include
#include
#include
#include
#include
#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
#include
#include
#include
#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
#include
#include
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
#include
#include
#include
#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, ','sizeof ()event);.
event=events events channel->();.
event.data=ptr static_cast <void*(>)channel;epoll_ctl
(,epollfd_, operationfd channel->(),& )event;return
;}
#
7、channel.h
ifndefTINY_MUDUO_CHANNEL_H_ #
defineTINY_MUDUO_CHANNEL_H_ #
include#
include#
include"eventloop.h" #
include"callback.h" namespace
enum tiny_muduo {
ChannelState , {
kNew,
kAdded}
kDeleted
;class
Channel public {
:Channel
(*EventLoop, loopconst int &) fd;~
Channel();void
HandleEvent ();void
SetReadCallback ()ReadCallback callback= {
read_callback_ :: stdmove()callback;}
void
SetWriteCallback ()WriteCallback callback= {
write_callback_ :: stdmove()callback;}
void
EnableReading ()|= {
events_ ( |EPOLLIN ) EPOLLPRI;Update
();}
void
EnableWriting ()|= {
events_ ; EPOLLOUTUpdate
();}
void
DisableAll ()= {
events_ 0 ;Update
();}
void
DisableWriting ()&= {
events_ ~ ;EPOLLOUTUpdate
();}
void
Update ()Update {
loop_->(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_} state
ChannelState ()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" #
includeusing
namespace ; tiny_muduoChannel
::Channel(*EventLoop, loopconst
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_ ) EPOLLOUTif {
()write_callback_write_callback_ {
();}
}
}
#
8、tcpconnection.h
ifndefTINY_MUDUO_TCPCONNECTION_H_ #
defineTINY_MUDUO_TCPCONNECTION_H_ #
include#
include#
include#
include#
include#
include#
include"callback.h" #
include"channel.h" #
include"buffer.h" #
include"httpcontent.h" using
:: std;stringnamespace
class tiny_muduo {
EventLoop ;class
TcpConnection : public :: stdenable_shared_from_this<TcpConnectionpublic> {
:enum
ConnectionState , {
kConnected}
kDisconnected
;TcpConnection
(*EventLoop, loopint) connfd;~
TcpConnection();void
SetConnectionCallback ()ConnectionCallback callback= {
connection_callback_ :: stdmove()callback;}
void
SetMessageCallback ()MessageCallback callback= {
message_callback_ :: stdmove()callback;}
void
SetCloseCallback ()CloseCallback callback= {
close_callback_ :: stdmove()callback;}
void
ConnectionEstablished ()= {
state_ ; kConnectedEnableReading
channel_->();connection_callback_
(shared_from_this(),& )input_buffer_;}
*
HttpContentGetHttpContent ()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 (constchar *, messageint ) len;void
Send (constchar *) messageSend { (,messagestrlen ()message);} int
fd ()const return { ; fd_} *
EventLooploop ()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 #
include#
include#
include"channel.h" #
include"buffer.h" using
namespace ; tiny_muduoTcpConnection
::TcpConnection(*EventLoop, loopint ) connfd:
loop_ ()loop,fd_
()connfd,state_
()kDisconnected,channel_
(newChannel (,loop_) fd_),shutdown_state_
(false)SetReadCallback {
channel_->(::stdbind(&::TcpConnection,HandleMessagethis ));SetWriteCallback
channel_->(::stdbind(&::TcpConnection,HandleWritethis ));}
TcpConnection
::~TcpConnection()//printf("TcpConnection::~TcpConnection destructor\n"); {
::
close()fd_;}
void
TcpConnection ::ConnectionDestructor()if {
( ==state_ ) kConnected= {
state_ ; kDisconnectedDisableAll
channel_->();}
Remove
loop_->(.channel_get());}
void
TcpConnection ::HandleClose()= {
state_ ; kDisconnectedDisableAll
channel_->();guard
TcpConnectionPtr (shared_from_this());close_callback_
()guard;}
void
TcpConnection ::HandleMessage()int {
= read_size . input_buffer_ReadFd()fd_;if
( 0read_size > )message_callback_ {
(shared_from_this(),& )input_buffer_;}
else if ( ==read_size 0 )HandleClose {
();}
}
void
TcpConnection ::HandleWrite()int {
= len . output_buffer_readablebytes();int
= remaining ; lenint
= send_size :: write(,fd_. output_buffer_Peek(),) remaining;-=
remaining ; send_size.
output_buffer_Retrieve()send_size;assert
(<=remaining ) len;if
( !.output_buffer_readablebytes())DisableWriting {
channel_->();}
}
void
TcpConnection ::Send(constchar *, messageint ) lenint {
= remaining ; lenint
= send_size 0 ;if
( !IsWritingchannel_->()&& . output_buffer_readablebytes()== 0 )= {
send_size :: write(,fd_, message) len;-=
remaining ; send_size}
assert
(<=remaining ) len;if
( 0remaining > ). {
output_buffer_Append(+message , send_size) remaining;if
( !IsWritingchannel_->())EnableWriting {
channel_->();}
}
}
void
TcpConnection ::Shutdown()if {
( !IsWritingchannel_->()):: {
shutdown(,fd_) SHUT_WR;=
shutdown_state_ true ;}
}
void
TcpConnection ::Send(*Buffer) bufferSend {
(Peekbuffer->(),readablebytes buffer->());RetrieveAll
buffer->();}
void
TcpConnection ::Send(const& string) messageSend {
(.messagedata(),. messagesize());}
#
9、buffer.h
ifndefTINY_MUDUO_BUFFER_H_ #
defineTINY_MUDUO_BUFFER_H_ #
include#
include #
include#
defineNDEBUG #
include #
includeusing
:: std;stringnamespace
static tiny_muduo {
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 (constchar *) messageAppend {
(,messagestrlen ()message);}
void
Append (constchar *, messageint ) lenMakeSureEnoughStorage {
()len;::
stdcopy(,message+ message , lenbeginwrite ());+=
write_index_ ; len}
void
Append (const& string) messageAppend {
(.messagedata(),. messagesize());}
void
Retrieve (int) lenassert {
(readablebytes()) >= len;if
( +len < read_index_ ) write_index_= {
read_index_ + read_index_ ; len}
else = {
write_index_ ; kPrePendIndex=
read_index_ ; write_index_}
}
void
RetrieveUntilIndex (constchar *) indexassert {
(beginwrite()) >= index;+=
read_index_ - index beginread ();}
void
RetrieveAll ()= {
write_index_ ; kPrePendIndex=
read_index_ ; write_index_}
RetrieveAsString
string (int) lenassert {
(+read_index_ <= len ) write_index_;=
string ret :: stdmove(PeekAsString()len);Retrieve
()len;return
; ret}
RetrieveAllAsString
string ()= {
string ret :: stdmove(PeekAllAsString());RetrieveAll
();return
; ret}
const
char *Peek ()const return {
beginread ();}
char
*Peek ()return {
beginread ();}
PeekAsString
string (int) lenreturn {
string (beginread(),beginread ()+ ) len;}
PeekAllAsString
string ()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) lenif {
( writablebytes()) >= lenreturn ;if
( writablebytes()+ prependablebytes ()+ >= kPrePendIndex ) len:: {
stdcopy(beginread(),beginwrite (),begin ()+ ) kPrePendIndex;=
write_index_ + kPrePendIndex readablebytes ();=
read_index_ ; kPrePendIndex}
else . {
buffer_resize(.buffer_capacity()+ ) len;}
}
private
:::
std<vectorchar;> buffer_int
; read_index_int
; write_index_}
;}
#
endif#
9、buffer.cc
include"buffer.h" #
includeusing
namespace ; tiny_muduoint
Buffer ::ReadFd(int) fdchar {
[ extrabuf65536]= 0 {};struct
iovec [ iv2];const
int = writable writablebytes ();[
iv0].=iov_base beginwrite ();[
iv0].=iov_len ; writable[
iv1].=iov_base ; extrabuf[
iv1].=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
ifndefTINY_MUDUO_THREAD_H_ #
defineTINY_MUDUO_THREAD_H_ #
include#
include#
include"latch.h" namespace
class tiny_muduo {
Thread public {
:typedef
:: std<functionvoid( );> ThreadFuncThread
(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 ()CountDown {
latch_->();=
latch_ nullptr ;func_
();}
}
;}
#
endif#
10、thread.cc
include"thread.h" #
include#
include"latch.h" using
namespace ; tiny_muduostatic
void *ThreadRun (void*) arg* {
ThreadData= ptr static_cast <*ThreadData(>)arg;RunOneFunc
ptr->();delete
; ptrreturn
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
ifndefTINY_MUDUO_EVENTLOOPTHREAD_H #
defineTINY_MUDUO_EVENTLOOPTHREAD_H #
include"thread.h" #
include"mutex.h" #
include"condition.h" namespace
class tiny_muduo {
EventLoop ;class
EventLoopThread public {
:EventLoopThread
();~
EventLoopThread();void
StartFunc ();*
EventLoopStartLoop ();private
:*
EventLoop; loop_;
Thread thread_;
MutexLock mutex_;
Condition cond_}
;}
#
endif#
11、eventloopthread.cc
include"eventloopthread.h" #
include#
include#
include"mutex.h" #
include"condition.h" #
include"eventloop.h" using
namespace ; tiny_muduoEventLoopThread
::EventLoopThread():
loop_ (nullptr),thread_
(::stdbind(&::EventLoopThread,StartFuncthis )),mutex_
(),cond_
()mutex_} {
EventLoopThread
::~EventLoopThread()} {*
EventLoopEventLoopThread ::StartLoop(). {
thread_StartThread();*
EventLoop= loop nullptr ;lock
{
MutexLockGuard ()mutex_;while
( ==loop_ nullptr ). {
cond_Wait();}
=
loop ; loop_}
return
; loop}
void
EventLoopThread ::StartFunc(); {
EventLoop looplock
{
MutexLockGuard ()mutex_;=
loop_ & ;loop.
cond_Signal();}
Loop
loop_->();lock
{
MutexLockGuard ()mutex_;=
loop_ nullptr ;}
}
#
12、eventloopthreadpool.h
ifndefTINY_MUDUO_EVENTLOOPTHREADPOOL_H_ #
defineTINY_MUDUO_EVENTLOOPTHREADPOOL_H_ #
include#
includenamespace
class tiny_muduo {
EventLoopThread ;class
EventLoop ;class
EventLoopThreadPool public {
:typedef
:: std<vector::std<unique_ptr;EventLoopThread>> Threadtypedef
:: std<vector*EventLoop;> LoopEventLoopThreadPool
(*EventLoop) loop;~
EventLoopThreadPool();void
SetThreadNums (int) thread_nums= {
thread_nums_ ; thread_nums}
void
StartLoop ();*
EventLoopNextLoop ();private
:*
EventLoop; base_loop_;
Thread threads_;
Loop loops_int
; thread_nums_int
; next_}
;}
#
endif#
12、eventloopthreadpool.cc
include"eventloopthreadpool.h" #
include#
include"eventloopthread.h" using
namespace ; tiny_muduoEventLoopThreadPool
::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(::stdunique_ptr<(EventLoopThread>)ptr);.
loops_emplace_back(StartLoopptr->());}
}
*
EventLoopEventLoopThreadPool ::NextLoop()* {
EventLoop= ret ; base_loop_if
( !.loops_empty())= {
ret [ loops_]next_;=
next_ ( +next_ 1 )% ; thread_nums_}
return
; ret}
#
2、httpserver相关文件
1、httpcontent.h
ifndefTINY_MUDUO_HTTPCONTENT_H_ #
defineTINY_MUDUO_HTTPCONTENT_H_ #
include#
include #
include"buffer.h" #
include"httprequest.h" #
include"httpparsestate.h" namespace
enum tiny_muduo {
HttpRequestParseLine , {
kLineOK,
kLineMore}
kLineErrno
;class
HttpContent public {
:HttpContent
();~
HttpContent();void
ParseLine (*Buffer) buffer;bool
ParseContent (*Buffer) buffer;bool
GetCompleteRequest ()return { == parse_state_ ; kParseGotCompleteRequest} const
& HttpRequestrequest ()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_muduoHttpContent
::HttpContent(): checked_index_ (0),parse_state_
()kParseRequestLine} {
HttpContent
::~HttpContent()} {void
HttpContent ::ParseLine(*Buffer) buffer= {
line_state_ ; kLineMoreif
( readablebytesbuffer->()== 0 )return ;int
= readable_index readablebytes buffer->();const
char *= buf beginread buffer->();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) bufferwhile {
( !=parse_state_ ) kParseErrnoParseLine {
()buffer;if
( ==line_state_ || kLineMore == line_state_ ) kLineErrnoif {
( ==line_state_ ) kLineErrno= {
parse_state_ ; kParseErrno=
checked_index_ 0 ;}
break
;}
const
char *= start beginread buffer->();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_ ) kParseGotCompleteRequestbreak {
;}
RetrieveUntilIndex
buffer->(+start ) checked_index_;=
checked_index_ 0 ;}
return
!= parse_state_ ; kParseErrno}
#
2、httprequest.h
ifndefTINY_MUDUO_HTTPREQUEST_H_ #
defineTINY_MUDUO_HTTPREQUEST_H_ #
include"httpparsestate.h" #
include#
includeusing
:: std;stringnamespace
static tiny_muduo {
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 (constchar *, startconst char *) end;void
ParseRequestLine (constchar *, startconst char *, end&
HttpRequestParseState) state;void
ParseHeaders (constchar *, startconst char *, end&
HttpRequestParseState) state;void
ParseBody (constchar *, startconst char *, end&
HttpRequestParseState) state;method
Method ()const return { ; method_} const
& stringpath ()const return { ; path_} const
& stringquery ()const return { ; query_} version
Version ()const return { ; version_} const
:: std<map,string& string>headers ()const return { ; headers_} GetHeader
string (const& string) headerconst 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#
include #
include"httpparsestate.h" using
namespace ; tiny_muduousing
:: tiny_muduo;Methodusing
:: tiny_muduo;HttpRequestParseStateHttpRequest
::HttpRequest()} {
HttpRequest
::~HttpRequest()} {
bool
HttpRequest ::ParseRequestMethod(constchar *, startconst char *) endmethod {
string (,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(constchar *, startconst char *, end&
HttpRequestParseState) stateconst {
{
char *= space :: stdfind(,start, end' ' );if
( ==space ) end= {
state ; kParseErrnoreturn
;}
if
( !ParseRequestMethod(,start) space)= {
state ; kParseErrnoreturn
;}
=
start + space 1 ;}
const
{
char *= space :: stdfind(,start, end' ' );if
( ==space ) end= {
state ; kParseErrnoreturn
;}
const
char *= query :: stdfind(,start, end'?' );if
( !=query ) end= {
path_ :: stdmove(string(,start) query);=
query_ :: stdmove(string(+query 1 ,) space);}
else = {
path_ :: stdmove(string(,start) space);}
=
start + space 1 ;}
const
{
int = httplen sizeof ()http/ sizeof (char)- 1 ;const
char *= httpindex :: stdsearch(,start, end, http+ http ) httplen;if
( ==httpindex ) end= {
state ; kParseErrnoreturn
;}
const
char = chr * (+httpindex ) httplen;if
( +httpindex + httplen 1 == && end ( ==chr '1' || == chr '0' ))if {
( ==chr '1' )= {
version_ ; kHttp11}
else = {
version_ ; kHttp10}
}
else = {
state ; kParseErrnoreturn
;}
}
=
state ; kParseHeaders}
void
HttpRequest ::ParseBody(constchar *, startconst char *, end&
HttpRequestParseState) state} {
void
HttpRequest ::ParseHeaders(constchar *, startconst char *, end&
HttpRequestParseState) stateif {
( ==start && end * ==start '\r' && * (+start 1 )== '\n' )= {
state ; kParseGotCompleteRequestreturn
;}
const
char *= colon :: stdfind(,start, end':' );if
( ==colon ) end= {
state ; kParseErrnoreturn
;}
const
char *= vaild + colon 1 ;while
( *(++vaild)!= ' ' )} {[
headers_::stdmove(string(,start) colon)]= :: stdmove(string(+colon 1 ,) vaild);return
;}
#
3、httpresponse.h
ifndefTINY_MUDUO_HTTPRESPONSE_H_ #
defineTINY_MUDUO_HTTPRESPONSE_H_ #
include#
include#
include"httprequest.h" using
:: std;stringnamespace
static tiny_muduo {
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_ :: stdmove()status_message;} void
SetCloseConnection (bool) close_connection= { close_connection_ ; close_connection} void
SetBodyType (const& string) type= { type_ ; type} void
SetBodyType (constchar *) type= { type_ ; type} void
SetBody (const& string) body= { body_ ; body} void
SetBody (constchar *) body= { body_ :: stdmove(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#
include#
include"buffer.h" using
namespace ; tiny_muduousing
:: std;stringconst
:: string HttpResponse=server_name_ "Tiny_muduo" ;void
HttpResponse ::AppendToBuffer(*Buffer) bufferchar {
[ buf32]= 0 {};snprintf
(,bufsizeof ()buf,"HTTP/1.1 %d " ,)status_code_;Append
buffer->()buf;Append
buffer->()status_message_;Append
buffer->()CRLF;if
( )close_connection_Append {
buffer->("Connection: close\r\n");}
else snprintf {
(,bufsizeof ()buf,"Content-Length: %zd\r\n" ,. body_size());// no need to memset this is longer than HTTP... one Append
buffer->()buf;Append
buffer->("Connection: Keep-Alive\r\n");}
Append
buffer->("Content-Type: ");Append
buffer->()type_;Append
buffer->()CRLF;Append
buffer->("Server: ");Append
buffer->()server_name_;Append
buffer->()CRLF;Append
buffer->()CRLF;Append
buffer->()body_;return
;}
#
4、httpparsestate.h
ifndefTINY_MUDUO_HTTPSTATE_H_ #
defineTINY_MUDUO_HTTPSTATE_H_ namespace
enum tiny_muduo {
HttpRequestParseState , {
kParseRequestLine,
kParseHeaders,
kParseBody,
kParseGotCompleteRequest,
kParseErrno}
;}
#
endif#
3、其他组件(mutex makefile等)
1、mutex
ifndefTINY_MUDUO_MUTEX_H_ #
defineTINY_MUDUO_MUTEX_H_ #
include"pthread.h" namespace
class tiny_muduo {
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_tmutex ()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
ifndefTINY_MUDUO_CONDITION_H_ #
defineTINY_MUDUO_CONDITION_H_ #
include"pthread.h" #
include"mutex.h" namespace
class tiny_muduo {
Condition public {
:Condition
(&MutexLock) mutex: mutex_ ()mutexpthread_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
ifndefTINY_MUDUO_LATCH_H_ #
defineTINY_MUDUO_LATCH_H_ #
include"mutex.h" #
include"condition.h" namespace
class tiny_muduo {
Latch public {
:Latch
(int) count: count_ ()count,mutex_ (),cond_ ()mutex_} {void
CountDown ()lock {
MutexLockGuard ()mutex_;--
;count_if
( ==count_ 0 ). {
cond_BroadCast();}
}
void
Wait ()lock {
MutexLockGuard ()mutex_;while
( 0count_ > ). {
cond_Wait();}
}
private
:int
; count_;
MutexLock mutex_;
Condition cond_}
;}
#
endif#
4、callback.h
ifndefTINY_MUDUO_CALLBACK_H_ #
defineTINY_MUDUO_CALLBACK_H_ #
include#
includeusing
:: std::placeholders;_1using
:: std::placeholders;_2using
:: std::placeholders;_3namespace
class tiny_muduo {
TcpConnection ;typedef
:: std<shared_ptr;TcpConnection> TcpConnectionPtrclass
Buffer ;typedef
:: std<functionvoid( const& TcpConnectionPtr,* Buffer);> ConnectionCallbacktypedef
:: std<functionvoid( const& TcpConnectionPtr,* Buffer);> MessageCallbacktypedef
:: std<functionvoid( );> ReadCallbacktypedef
:: std<functionvoid( );> WriteCallbacktypedef
:: std<functionvoid( 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的工作状态
但是毕竟走到现在了 还是得坚持下去 之后再回头看看这里 可能也觉得别有一番感觉 哈哈
各位下一篇见了~
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)