有限状态机解析http请求
http_conn对象记录每一个链接的状态
epoll + 半同步半反应堆线程池并发处理连接
20210709更新:
实现方法:
(先做两个网页放进去,doc_root目录改成资源文件所在目录)
make server
./server 8888(./server + 端口号)
浏览器端:
公网ip:端口号/文件名
CXX ?= g++
DEBUG ?= 1
ifeq ($(DEBUG), 1)
CXXFLAGS += -g
else
CXXFLAGS += -O2
endif
server: main.cpp http_conn.cpp
$(CXX) -o server $^ $(CXXFLAGS) -lpthread -g
clean:
rm -r server
locker.h
//线程同步机制包装类
#ifndef LOCKER_H
#define LOCKER_H
#include <exception>
#include <pthread.h>
#include <semaphore.h>
//封装信号量的类
class sem
{
public:
sem()
{
if(sem_init(&m_sem, 0, 0) != 0)
{
throw std::exception();
}
}
//销毁信号量
~sem()
{
sem_destroy(&m_sem);
}
//等待信号量
bool wait()
{
return sem_wait(&m_sem) == 0;
}
bool post()
{
return sem_post(&m_sem) == 0;
}
private:
sem_t m_sem;
};
class locker
{
public:
locker()
{
if(pthread_mutex_init(&m_mutex, NULL) != 0)
{
throw std::exception();
}
}
~locker()
{
pthread_mutex_destroy(&m_mutex);
}
bool lock()
{
return pthread_mutex_lock(&m_mutex) == 0;
}
bool unlock()
{
return pthread_mutex_unlock(&m_mutex) == 0;
}
private:
pthread_mutex_t m_mutex;
};
//phtread
class cond
{
public:
cond()
{
if(pthread_mutex_init(&m_mutex, NULL) != 0)
{
throw std::exception();
}
if(pthread_cond_init(&m_cond, NULL) != 0)
{
//出现问题得释放已经分配的资源
pthread_mutex_destroy(&m_mutex);
throw std::exception();
}
}
~cond()
{
pthread_mutex_destroy(&m_mutex);
pthread_cond_destroy(&m_cond);
}
bool wait()
{
int ret = 0;
pthread_mutex_lock(&m_mutex);
ret = pthread_cond_wait(&m_cond, &m_mutex);
pthread_mutex_unlock(&m_mutex);
return ret == 0;
}
bool signal()
{
return pthread_cond_signal(&m_cond) == 0;
}
private:
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
};
#endif
threadpool.h
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include <list>
#include <cstdio>
#include <exception>
#include <pthread.h>
#include "locker.h"
//线程池类,将他定义为模板类是为了代码复用
template<typename T>
class threadpool
{
public:
/*thread_number是线程池中线程的数量,max_requests是请求队列中最多允许的、等待处理的请求的数量*/
threadpool( int thread_number = 8, int max_request = 10000);
~threadpool();
bool append(T *request);
private:
/*工作线程运行的函数,它不断从工作队列中取出任务并执行之*/
static void *worker(void *arg);
void run();
private:
int m_thread_number; //线程池中的线程数
int m_max_requests; //请求队列中允许的最大请求数
pthread_t *m_threads; //描述线程池的数组,其大小为m_thread_number
std::list<T *> m_workqueue; //请求队列
locker m_queuelocker; //保护请求队列的互斥锁
sem m_queuestat; //是否有任务需要处理
bool m_stop; //是否结束线程
};
template <typename T>
threadpool<T>::threadpool(int thread_number, int max_requests) : m_thread_number(thread_number), m_max_requests(max_requests), m_stop(false),m_threads(NULL)
{
printf("初始化线程池!\n");
if (thread_number <= 0 || max_requests <= 0)
throw std::exception();
m_threads = new pthread_t[m_thread_number];
if (!m_threads)
throw std::exception();
for (int i = 0; i < thread_number; ++i)
{
if (pthread_create(m_threads + i, NULL, worker, this) != 0)
{
delete[] m_threads;
throw std::exception();
}
if (pthread_detach(m_threads[i]))
{
delete[] m_threads;
throw std::exception();
}
}
}
template <typename T>
threadpool<T>::~threadpool()
{
printf("线程池析构!\n");
delete[] m_threads;
}
template <typename T>
bool threadpool<T>::append(T *request)
{
printf("append()\n");
m_queuelocker.lock();
if (m_workqueue.size() > m_max_requests)
{
m_queuelocker.unlock();
return false;
}
m_workqueue.push_back(request);
m_queuelocker.unlock();
m_queuestat.post();
return true;
}
template <typename T>
void *threadpool<T>::worker(void *arg)
{
printf("work()!\n");
threadpool *pool = (threadpool *)arg;
pool->run();
return pool;
}
template <typename T>
void threadpool<T>::run()
{
printf("run()!\n");
while(!m_stop)
{
m_queuestat.wait();
m_queuelocker.lock();
if(m_workqueue.empty())
{
m_queuelocker.unlock();
continue;
}
T * request = m_workqueue.front();
m_workqueue.pop_front();
m_queuelocker.unlock();
if(!request)
{
continue;
}
printf("process()\n");
request->process();
}
}
#endif
http_conn.h
#ifndef HTTP_CONN_H
#define HTTP_CONN_H
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.