文章目录
- 前引
- (十一)---- 花费数天完善代码寻找瓶颈 修修改改代码初具规模 罗列目前全部代码
- 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(增加了屏蔽SIGPIPE信号处理)
- 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(增加了__thread 线程局部存储设施)
- 11、eventloopthread.h(无修改)
- 11、eventloopthread.cc(无修改)
- 12、eventloopthreadpool.h(无修改)
- 12、eventloopthreadpool.cc(无修改)
- 2、httpserver相关文件
- 3、其他组件(mutex makefile等)
- 结束语
前引
这部分还是代码罗列
但相比第九篇的代码 很多地方还是有非常大的改变的 尤其是http分析那块位置 已经算是大改了
然后就是buffer的一些地方改动了 还有很多地方能进行优化的地方 我目前觉得挺有意义的 我就做了优化
现在性能 在和linya学长的webserver 关闭输出和日志库进行对比后 发现我在弱势的方面 也就是短链接上 竟然不输没有很大的劣势
这也说明 没有很明显的性能陷阱了 很多地方我觉得能优化的 我也做了优化 下面也就不再列出来目前性能了
由于每个人机器性能不同 而且前几篇的我的博客 虚拟机的处理器个数我设置的是4 应该是一个比较合理的数字 现在我设置为了6 且每个处理器的核数我设置为了2 反而性能下降了很多
后面最后我再花时间 看看怎么把处理器个数设置的比较合理 但是在同一个机器上跑 我们不用在乎每秒处理是多少 能和已经公认 比较成熟的服务器处理横向比较 在相同输出情况下 性能差距不大或者还占优的话 那就足够了
也有可能 目前还没有设置linya学长的服务器 echo输出和我的一样 也有可能是这个原因导致性能下降… 后面再探究了
好了不说那么多了 代码相比第九篇又多了… 这里感觉前引没图片少了点什么 那就用cloc
我们上一篇介绍的代码统计工具来统计一下目前的代码行数 作为这一章的图片吧
(十一)---- 花费数天完善代码寻找瓶颈 修修改改代码初具规模 罗列目前全部代码
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/html");
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(const HttpResponseCallback& response_callback) {
response_callback_ = response_callback;
}
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();
}
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 <map>
#include "callback.h"
#include "eventloop.h"
#include "acceptor.h"
#include "eventloopthreadpool.h"
#include "tcpconnection.h"
#include "noncopyable.h"
namespace tiny_muduo {
class Address;
class TcpServer : public NonCopyAble {
public:
TcpServer(EventLoop* loop, const Address& address);
~TcpServer();
void Start() {
threads_->StartLoop();
loop_->RunOneFunc(std::bind(&Acceptor::Listen, acceptor_.get()));
}
void SetConnectionCallback(ConnectionCallback&& callback) {
connection_callback_ = std::move(callback);
}
void SetConnectionCallback(const ConnectionCallback& callback) {
connection_callback_ = callback;
}
void SetMessageCallback(MessageCallback&& callback) {
message_callback_ = std::move(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::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"
#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_->RunOneFunc(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 <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <memory>
#include <functional>
#include "noncopyable.h"
namespace tiny_muduo {
class EventLoop;
class Address;
class Channel;
class Acceptor : public NonCopyAble {
public:
typedef std::function<void (int)> NewConnectionCallback;
Acceptor(EventLoop* loop, const Address& address);
~Acceptor();
void BindListenFd(const Address& address);
void Listen();
void NewConnection();
int SetSockoptKeepAlive(int fd) {
int option_val = 1;
return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
&option_val, static_cast<socklen_t>(sizeof(option_val)));
}
int SetSockoptReuseAddr(int fd) {
int option_val = 1;
return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
&option_val, static_cast<socklen_t>(sizeof(option_val)));
}
int SetSockoptTcpNoDelay(int fd) {
int option_val = 1;
return setsockopt(fd, IPPROTO_TCP, SO_KEEPALIVE,
&option_val, static_cast<socklen_t>(sizeof(option_val)));
}
void SetNewConnectionCallback(const NewConnectionCallback& callback) {
new_connection_callback_ = callback;
}
void SetNewConnectionCallback(NewConnectionCallback&& callback) {
new_connection_callback_ = std::move(callback);
}
private:
EventLoop* loop_;
int listenfd_;
int idlefd_;
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 <netinet/tcp.h>
#include <functional>
#include "address.h"
#include "channel.h"
using namespace tiny_muduo;
Acceptor::Acceptor(EventLoop* loop, const Address& address)
: loop_(loop),
listenfd_(::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP)),
idlefd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)),
channel_(new Channel(loop_, listenfd_)) {
SetSockoptReuseAddr(listenfd_);
SetSockoptKeepAlive(listenfd_);
BindListenFd(address);
channel_->SetReadCallback(std::bind(&Acceptor::NewConnection, this));
}
Acceptor::~Acceptor() {
channel_->DisableAll();
loop_->Remove(channel_.get());
::close(listenfd_);
}
void Acceptor::BindListenFd(const Address& addr) {
struct sockaddr_in address;
bzero((char*)&address, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
address.sin_port = htons(addr.port());
int ret = bind(listenfd_, (struct sockaddr*)(&address), sizeof(address));
assert(ret != -1);
(void)ret;
}
void Acceptor::Listen() {
int ret = listen(listenfd_, SOMAXCONN);
assert(ret != -1);
(void)ret;
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);
if (connfd < 0) {
if (errno == EMFILE) {
::close(idlefd_);
idlefd_ = ::accept(listenfd_, NULL, NULL);
::close(idlefd_);
idlefd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC);
}
return;
}
assert(connfd > 0);
if (SetSockoptKeepAlive(connfd) == -1) {
printf("Acceptor::NewConnection SetSockoptKeepAlive failed\n");
close(connfd);
return;
}
if (SetSockoptTcpNoDelay(connfd) == -1) {
printf("Acceptor::NewConnection SetSockoptTcpNoDelay failed\n");
close(connfd);
return;
}
new_connection_callback_(connfd);
}
5、eventloop.h(无修改)
#ifndef TINY_MUDUO_EVENTLOOP_H_
#define TINY_MUDUO_EVENTLOOP_H_
#include <stdint.h>
#include <unistd.h>
#include <assert.h>
#include <sys/eventfd.h>
#include <pthread.h>
#include <vector>
#include <functional>
#include <memory>
#include "mutex.h"
#include "epoller.h"
#include "currentthread.h"
#include "noncopyable.h"
namespace tiny_muduo {
class Epoller;
class Channel;
class EventLoop : public NonCopyAble {
public:
typedef std::vector<Channel*> Channels;
typedef std::function<void()> BasicFunc;
typedef std::vector<BasicFunc> ToDoList;
EventLoop();
~EventLoop();
bool IsInThreadLoop() { return CurrentThread::tid() == 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:
pid_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(增加了屏蔽SIGPIPE信号处理)
#include "eventloop.h"
#include <unistd.h>
#include <sys/eventfd.h>
#include <pthread.h>
#include <signal.h>
#include <utility>
#include "mutex.h"
#include "channel.h"
using namespace tiny_muduo;
namespace {
class IgnoreSigPipe {
public:
IgnoreSigPipe() {
::signal(SIGPIPE, SIG_IGN);
}
};
IgnoreSigPipe initObj;
} // namespace
EventLoop::EventLoop()
: tid_(CurrentThread::tid()),
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());
close(wakeup_fd_);
}
void EventLoop::Loop() {
assert(IsInThreadLoop());
while (true) {
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;
ssize_t read_size = ::read(wakeup_fd_, &read_one_byte, sizeof(read_one_byte));
(void) read_size;
assert(read_size == 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;
int write_size = ::write(wakeup_fd_, &write_one_byte, sizeof(write_one_byte));
(void) write_size;
assert(write_size == 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 <map>
#include "noncopyable.h"
static const int kDefaultEvents = 16;
namespace tiny_muduo {
class Channel;
class Epoller : public NonCopyAble {
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::map<int, Channel*> ChannelMap;
int epollfd_;
Events events_;
ChannelMap channels_;
};
}
#endif
6、epoller.cc(无修改)
#include "epoller.h"
#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;
event.events = channel->events();
event.data.ptr = static_cast<void*>(channel);
if (epoll_ctl(epollfd_, operation, channel->fd(), &event) < 0) {
printf("Epoller::UpdateChannel epoll_ctl SYS_ERR\n");
}
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"
#include "noncopyable.h"
namespace tiny_muduo {
enum ChannelState {
kNew,
kAdded,
kDeleted
};
class Channel : public NonCopyAble {
public:
Channel(EventLoop* loop, const int& fd);
~Channel();
void HandleEvent();
void SetReadCallback(ReadCallback&& callback) {
read_callback_ = std::move(callback);
}
void SetReadCallback(const ReadCallback& callback) {
read_callback_ = callback;
}
void SetWriteCallback(WriteCallback&& callback) {
write_callback_ = std::move(callback);
}
void SetWriteCallback(const WriteCallback& callback) {
write_callback_ = 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"
#include "noncopyable.h"
using std::string;
namespace tiny_muduo {
class EventLoop;
class TcpConnection : public std::enable_shared_from_this<TcpConnection>, NonCopyAble {
public:
enum ConnectionState {
kConnected,
kDisconnected
};
TcpConnection(EventLoop* loop,int connfd);
~TcpConnection();
void SetConnectionCallback(const ConnectionCallback& callback) {
connection_callback_ = callback;
}
void SetConnectionCallback(ConnectionCallback&& callback) {
connection_callback_ = std::move(callback);
}
void SetMessageCallback(const MessageCallback& callback) {
message_callback_ = callback;
}
void SetMessageCallback(MessageCallback&& callback) {
message_callback_ = std::move(callback);
}
void SetCloseCallback(const CloseCallback& callback) {
close_callback_ = callback;
}
void SetCloseCallback(CloseCallback&& callback) {
close_callback_ = std::move(callback);
}
void ConnectionEstablished() {
state_ = kConnected;
channel_->EnableReading();
connection_callback_(shared_from_this(), &input_buffer_);
}
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_; }
HttpContent* GetHttpContent() { return &content_; }
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"
#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() {
::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();
} else {
printf("TcpConnection::HandleMessage Read SYS_Err\n");
}
}
void TcpConnection::HandleWrite() {
if (channel_->IsWriting()) {
int len = output_buffer_.readablebytes();
int remaining = len;
int send_size = ::write(fd_, output_buffer_.Peek(), remaining);
if (send_size < 0) {
assert(send_size > 0);
if (errno != EWOULDBLOCK) {
printf("TcpConnection::HandleWrite Write SYS_ERR\n");
}
return;
}
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);
if (send_size >= 0) {
remaining -= send_size;
} else {
if (errno != EWOULDBLOCK) {
printf("TcpConnection::Send Write SYS_ERR\n");
}
return;
}
}
assert(remaining <= len);
if (remaining > 0) {
output_buffer_.Append(message + send_size, remaining);
if (!channel_->IsWriting()) {
channel_->EnableWriting();
}
}
}
void TcpConnection::Shutdown() {
shutdown_state_ = true;
if (!channel_->IsWriting()) {
int ret = ::shutdown(fd_, SHUT_WR);
if (ret < 0) {
printf("TcpConnection::Shutdown shutdown SYS_ERR\n");
}
}
}
void TcpConnection::Send(Buffer* buffer) {
if (state_ == kDisconnected) return;
Send(buffer->Peek(), buffer->readablebytes());
buffer->RetrieveAll();
}
void TcpConnection::Send(const string& message) {
if (state_ == kDisconnected) return;
Send(message.data(), message.size());
}
9、buffer.h(增加了部分函数 修正了一些错误代码)
#ifndef TINY_MUDUO_BUFFER_H_
#define TINY_MUDUO_BUFFER_H_
#include <vector>
#include <algorithm>
#include <string>
#include <assert.h>
#include <cstring>
#include "noncopyable.h"
using std::string;
namespace tiny_muduo {
static const int kPrePendIndex = 8;
static const int kInitialSize = 1024;
static const char* kCRLF = "\r\n";
class Buffer : public NonCopyAble {
public:
Buffer() : buffer_(kInitialSize), 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_; }
const char* FindCRLF() const {
const char* find = std::search(Peek(), beginwrite(), kCRLF, kCRLF + 2);
return find == beginwrite() ? nullptr : find;
}
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_ += len;
} else {
RetrieveAll();
}
}
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_.size() - 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(write_index_ + 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"
#include "noncopyable.h"
namespace tiny_muduo {
class Thread : public NonCopyAble {
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(增加了__thread 线程局部存储设施)
#include "thread.h"
#include <unistd.h>
#include <pthread.h>
#include "latch.h"
using namespace tiny_muduo;
namespace CurrentThread {
__thread int t_cachedTid = 0;
void CacheTid() {
if (t_cachedTid == 0) {
t_cachedTid = ::gettid();
}
}
} // namespace CurrentThread;
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"
#include "noncopyable.h"
namespace tiny_muduo {
class EventLoop;
class EventLoopThread : public NonCopyAble {
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>
#include "noncopyable.h"
namespace tiny_muduo {
class EventLoopThread;
class EventLoop;
class EventLoopThreadPool : public NonCopyAble {
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),
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_++];
if (next_ == static_cast<int>(loops_.size())) next_ = 0;
}
return ret;
}
2、httpserver相关文件
1、httpcontent.h(新增长连接处理Reset函数)
#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 {
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() {
HttpRequest tmp;
request_.Swap(tmp);
parse_state_ = kParseRequestLine;
}
private:
HttpRequest request_;
HttpRequestParseState parse_state_;
};
}
#endif
1、httpcontent.cc(大幅度修改ParseContent函数 优化逻辑处理)
#include "httpcontent.h"
#include <algorithm>
#include "httprequest.h"
#include "httpparsestate.h"
using namespace tiny_muduo;
HttpContent::HttpContent() : parse_state_(kParseRequestLine) {
}
HttpContent::~HttpContent() {}
bool HttpContent::ParseContent(Buffer* buffer) {
bool linemore = true;
bool parseok = true;
const char* CRLF = nullptr;
while (linemore) {
CRLF = nullptr;
if (parse_state_ == kParseRequestLine) {
CRLF = buffer->FindCRLF();
if (CRLF) {
parseok = request_.ParseRequestLine(buffer->Peek(), CRLF);
if (parseok) {
parse_state_ = kParseHeaders;
} else {
linemore = false;
}
} else {
linemore = false;
}
} else if (parse_state_ == kParseHeaders) {
CRLF = buffer->FindCRLF();
if (CRLF) {
const char* colon = std::find((const char*)buffer->Peek(), CRLF, ':');
if (colon == CRLF) {
parse_state_ = kParseGotCompleteRequest;
linemore = false;
} else {
parseok = request_.ParseHeaders(buffer->Peek(), colon, CRLF);
if (!parseok) linemore = false;
}
} else {
linemore = false;
}
} else if (parse_state_ == kParseGotCompleteRequest) {
linemore = false;
} else if (parse_state_ == kParseBody) {
}
if (CRLF) {
buffer->RetrieveUntilIndex(CRLF + 2);
}
}
return parseok;
}
2、httprequest.h(增加Swap函数 方便长连接)
#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 {
kUnknown,
kHttp10,
kHttp11
};
class HttpRequest {
public:
HttpRequest();
~HttpRequest();
bool ParseRequestMethod(const char* start, const char* end);
bool ParseRequestLine(const char* start, const char* end);
bool ParseHeaders(const char* start, const char* colon, const char* end);
bool ParseBody(const char* start, const char* end);
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_; }
void Swap(HttpRequest& req);
string GetHeader(const string& header) const {
string ret;
auto iter = headers_.find(header);
return iter == headers_.end() ? ret : iter->second;
}
private:
Method method_;
Version version_;
string path_;
string query_;
std::map<string, string> headers_;
};
}
#endif
2、httprequest.cc(大幅度修改解析过程 优化处理)
#include "httprequest.h"
#include <utility>
#include <algorithm>
#include <string>
#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;
}
bool HttpRequest::ParseRequestLine(const char* start, const char* end) {
const char* space = nullptr;
space = std::find(start, end, ' ');
if (space == end) {
return false;
}
if (!ParseRequestMethod(start, space)) {
return false;
}
start = space + 1;
space = std::find(start, end, ' ');
if (space == end) {
return false;
}
const char* query = std::find(start, end, '?');
if (query != end) {
path_.assign(start, query);
query_.assign(query + 1, space);
} else {
path_.assign(start, space);
}
start = space + 1;
bool parsehttp = (start + 8 == end) && std::equal(start, end - 1, http);
if (!parsehttp || (*(end - 1) != '0' && *(end - 1) != '1')) {
version_ = kUnknown;
return false;
}
if (*(end - 1) == '0') {
version_ = kHttp10;
} else {
version_ = kHttp11;
}
return true;
}
bool HttpRequest::ParseBody(const char* start, const char* end) { return true; }
bool HttpRequest::ParseHeaders(const char* start, const char* colon, const char* end) {
const char* vaildstart = colon + 1;
while(*vaildstart == ' ') { ++vaildstart; }
headers_[std::move(string(start, colon))] = std::move(string(vaildstart, end));
return true;
}
void HttpRequest::Swap(HttpRequest& req) {
method_ = req.method_;
version_ = req.version_;
path_.swap(req.path_);
query_.swap(req.query_);
headers_.swap(req.headers_);
}
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 SetBody(const string& body) { body_ = body; }
void AppendToBuffer(Buffer* buffer);
bool CloseConnection() { return close_connection_; }
private:
static const string server_name_;
HttpStatusCode status_code_;
string status_message_;
string body_;
string type_;
bool close_connection_;
};
}
#endif
3、httpresponse.cc(大幅度优化输入过程 取缔string作为中间变量存储)
#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(构造函数添加了explicit参数)
#ifndef TINY_MUDUO_MUTEX_H_
#define TINY_MUDUO_MUTEX_H_
#include <pthread.h>
#include "noncopyable.h"
namespace tiny_muduo {
class MutexLock : public NonCopyAble {
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:
explicit MutexLockGuard(MutexLock& mutex) : mutex_(mutex) {
mutex_.Lock();
}
~MutexLockGuard() {
mutex_.Unlock();
}
private:
MutexLock& mutex_;
};
}
#endif
2、condition.h(构造函数添加了explicit参数)
#ifndef TINY_MUDUO_CONDITION_H_
#define TINY_MUDUO_CONDITION_H_
#include <pthread.h>
#include "mutex.h"
#include "noncopyable.h"
namespace tiny_muduo {
class Condition : public NonCopyAble {
public:
explicit Condition(MutexLock& mutex) : mutex_(mutex) {
pthread_cond_init(&cond_, nullptr);
}
~Condition() {
pthread_cond_destroy(&cond_);
}
bool Wait() {
return pthread_cond_wait(&cond_, mutex_.mutex()) == 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(构造函数添加了explicit参数)
#ifndef TINY_MUDUO_LATCH_H_
#define TINY_MUDUO_LATCH_H_
#include "mutex.h"
#include "condition.h"
#include "noncopyable.h"
namespace tiny_muduo {
class Latch : public NonCopyAble {
public:
explicit 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、noncopyable.h(新增文件)
#ifndef TINY_MUDUO_NONCOPYABLE_H_
#define TINY_MUDUO_NONCOPYABLE_H_
namespace tiny_muduo {
class NonCopyAble {
protected:
NonCopyAble() {}
~NonCopyAble() {}
private:
NonCopyAble(const NonCopyAble&) = delete;
NonCopyAble& operator=(const NonCopyAble&) = delete;
};
} // namespace tiny_muduo
#endif
6、makefile(增加了 -O优化以及DNDEBUG 默认O3优化)
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
NDEBUG = -DNDEBUG
BUILD = -O3 -DNDEBUG
webserver : $(OBJS)
$(CC) $^ -o $@ $(BUILD)
main.o : main.cc eventloop.h address.h httpserver.h httprequest.h httpresponse.h\
httpresponsefile.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
httpserver.o : httpserver.cc httpserver.h buffer.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
httpresponse.o : httpresponse.cc httpresponse.h buffer.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
httpcontent.o : httpcontent.cc httpcontent.h httprequest.h httpparsestate.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
httprequest.o : httprequest.cc httprequest.h httpparsestate.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
tcpserver.o : tcpserver.cc tcpserver.h acceptor.h tcpconnection.h\
eventloopthreadpool.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
acceptor.o : acceptor.cc acceptor.h address.h channel.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
channel.o : channel.cc channel.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
eventloop.o : eventloop.cc eventloop.h channel.h mutex.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
eventloopthreadpool.o : eventloopthreadpool.cc eventloopthreadpool.h eventloopthread.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
eventloopthread.o : eventloopthread.cc eventloopthreadpool.h mutex.h\
condition.h eventloop.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
thread.o : thread.cc thread.h latch.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
epoller.o : epoller.cc epoller.h channel.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
tcpconnection.o : tcpconnection.cc tcpconnection.h \
channel.h buffer.h httpcontent.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
buffer.o : buffer.cc buffer.h
$(CC) $(CFLAG) $< -o $@ $(BUILD)
.PHONY : clean
debug: $(OBJS)
$(CC) $^ -o webserver
release: webserver
clean:
rm *.o
结束语
终于给整完了 去次晚饭了
回寝室休息一会去啦 哈哈哈 我好喜欢这个byebye的表情
那这一篇就写到这里 下一篇再见啦~ ヾ( ̄▽ ̄)ByeBye