从零开始自制实现WebServer(九)---- 目前总览代码如下 得继续脚步前行


全流程实现博客链接


从零开始自制实现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的工作状态

但是毕竟走到现在了 还是得坚持下去 之后再回头看看这里 可能也觉得别有一番感觉 哈哈

各位下一篇见了~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Love 6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值