先定义一个锁类的头文件,其中包含互斥锁和信号量
#include <pthread.h>
#include <semaphore.h>
class locker{
private:
pthread_mutex_t mutex;
public:
locker()
{
pthread_mutex_init(&mutex,NULL);
}
~locker()
{
pthread_mutex_destroy(&mutex);
}
bool lock()
{
return pthread_mutex_lock(&mutex)==0;
}
bool unlock()
{
return pthread_mutex_unlock(&mutex)==0;
}
};
class sem{
private:
sem_t m_sem;
public:
sem()
{
sem_init(&m_sem,0,0);
}
~sem()
{
sem_destroy(&m_sem);
}
bool wait()
{
return sem_wait(&m_sem);
}
bool post()
{
return sem_post(&m_sem);
}
};
一个包含要处理的文件描述符类的头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include"epoller.h"
class basetask{
private:
int connfd;//客户端的文件描述符
public:
basetask(int a):connfd(a){}
void work()
{
/*发送html文件*/
int p=open("xia.html",O_RDONLY);
char myhtml[1024];
strcpy(myhtml,"HTTP/1.0 200 OK\r\n");
strcat(myhtml,"Server: xiakaiwei\r\n");
strcat(myhtml,"Content-type: text/html\r\n");
strcat(myhtml,"Connection: close\r\n");
char text[1024]={0};
int read_size=read(p,text,sizeof(text)-1);
char newbuff[1024];
sprintf(newbuff,"Content-Length: %d\r\n\r\n",read_size);
strcat(myhtml,newbuff);
strcat(myhtml,text);
write(connfd,myhtml,sizeof(myhtml));
printf("html文本发送完毕\n");
close(connfd);
}
};
存放epollfd类的头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<sys/epoll.h>
class epoller{
private:
int epollfd;//事件监听空间
public:
epoller()
{
epollfd=epoll_create(5);
}
int getepollfd()
{
return epollfd;
}
int setnonblocking(int fd)
{
int old_option=fcntl(fd,F_GETFL);
int new_option=old_option | O_NONBLOCK;
fcntl(fd,F_SETFL,new_option);
return old_option;
}
void addfd(int fd)
{
epoll_event event;
event.data.fd=fd;
event.events=EPOLLIN | EPOLLET;
epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&event);
setnonblocking(fd);
}
void removefd(int fd)
{
epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,NULL);
close(fd);
}
};
线程池头文件
#include <pthread.h>
#include <algorithm>
#include <iostream>
#include "basetask.h"
#include <stdbool.h>
#include<list>
#include"locker.h"
using namespace std;
class threadpool{
private:
list<basetask*>Task;
locker list_lock;
sem list_sem;
public:
threadpool()
{
this->createthread();
}
bool isempty()
{
return this->Task.empty();
}
void createthread()
{
pthread_t id;
for(int i=0;i<8;i++)
{
pthread_create(&id,NULL,runthread,this);
}
}
basetask* poptask()
{
list_lock.lock();
basetask *end=Task.front();
Task.pop_front();
list_lock.unlock();
return end;
}void pushback(int fd)
{
basetask *task=new basetask(fd);
list_lock.lock();
Task.push_back(task);
cout<<"此时任务队列个数:"<<Task.size()<<endl;
list_lock.unlock();
list_sem.post();
}
private:
static void *runthread(void *poll)
{
threadpool *p=(threadpool*)poll;
pthread_detach(pthread_self());
while(1)
{
p->list_sem.wait();
basetask *task=p->poptask();
cout<<"线程"<<pthread_self()<<"取得任务"<<endl;
task->work();
}
}
};
main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include"threadpool.h"
int init()
{
int listenfd;
struct sockaddr_in server_address;
memset(&server_address,0,sizeof(server_address));
server_address.sin_addr.s_addr=inet_addr("127.0.0.1");
server_address.sin_family=PF_INET;
server_address.sin_port=htons(atoi("80"));
listenfd=socket(PF_INET,SOCK_STREAM,0);
if(listenfd==-1)
{
printf("socket error!\n");
}
int ret=bind(listenfd,(struct sockaddr *)&server_address,sizeof(server_address));
if(ret==-1)
{
printf("bind erroe!\n");
}
ret=listen(listenfd,5);
if(ret==-1)
{
printf("listen error!\n");
}
return listenfd;
}
int main()
{
int listenfd=init();
epoller epo;
epo.addfd(listenfd);
epoll_event events[8];
while(1)
{
int numbers=epoll_wait(epo.getepollfd(),events,8,-1);
for(int i=0;i<numbers;i++)
{
int sockfd=events[i].data.fd;
if(sockfd==listenfd)
{
struct sockaddr_in client_address;
socklen_t client_address_len=sizeof(client_address);
int client_sockfd=accept(listenfd,(struct sockaddr*)&client_address,&client_address_len);
epo.addfd(client_sockfd);
}
else if(events[i].events & EPOLLIN)
{
printf("可读\n");
while(1)
{
char buff[1024];
int revc_size=recv(sockfd,buff,sizeof(buff),0);
if(revc_size>0)
{
printf("%s\n",buff);
}
else if(revc_size==0)
{
printf("连接关闭\n");
break;
}
else
{
break;
}
}
threadpool*pool=new threadpool;
pool->pushback(sockfd);
}
}
}
}
主函数采用reactor模式网页发送GET请求后,主函数将basetask放入任务队列中并释放信号量,线程池中线程等待信号量的释放,其中之一的线程争抢到锁后进行工作。
在firefox中输入127.0.0.1后可以看到,终端收到了两个GET请求并将内容打印了出来,然后发送了一个简单的html文本。
(没搞懂网页发送的第二个GET请求是什么意思)