int main(int argc,char* argv[]){
ARGS_CHECK(argc,4);
int threadNum = atoi(argv[3]);
threadpool_t threadpool;
threadPoolInit(&threadpool,threadNum);
threadPoolStart(&threadpool);
int listenFd = 0;
tcpInit(&listenFd,argv[1],argv[2]);
int epollfd = epoll_create(1);
ERROR_CHECK(epollfd,-1,"epoll_create");
epollAdd(epollfd,listenFd);
int readyNum = 0;
struct epoll_event evs[2];
memset(&evs,0,sizeof(evs));
int clientFd = 0;
while(1){
readyNum = epoll_wait(epollfd,evs,2,-1);
for(int index = 0;index < readyNum;++index){
if(evs[index].data.fd == listenFd){
clientFd = accept(listenFd,NULL,NULL);
if(clientFd < 0){
perror("accept");
return -1;
}
pNode_t pNew = (pNode_t)calloc(1,sizeof(node_t));
pNew->client = clientFd;
pthread_mutex_lock(&threadpool.que.mutex);
queInsert(&threadpool.que,pNew);
pthread_mutex_unlock(&threadpool.que.mutex);
pthread_cond_signal(&threadpool.que.cond);
}
}
}
close(listenFd);
return 0;
}
第一步:定义相关结构体
- 线程池结构体:线程数量,任务队列,线程池开启标志位,保存线程ID的数组
- 任务队列结构体:头尾指针,队列大小,互斥锁,信号量
- 任务节点:记录客户的套接字的描述符,指向下一个节点的指针。
typedef struct Node{
int client;
struct Node* pNext;
}node_t,*pNode_t;
typedef struct{
pNode_t pHead,pTail;
int size;
pthread_mutex_t mutex;
pthread_cond_t cond;
}que_t,*pQue_t;
typedef struct{
que_t que;
int threadNums;
bool isStar;
pthread_t* pThid;
}threadpool_t,*pThreadpool_t;
第二步:线程池的初始化和开启
void threadPoolInit(pThreadpool_t pthreadpool,int threadNum){
memset(pthreadpool,0,sizeof(threadpool_t));
queInit(&pthreadpool->que);
pthreadpool->threadNums = threadNum;
pthreadpool->isStar = false;
pthreadpool->pThid =(pthread_t*)calloc(threadNum,sizeof(pthread_t));
}
void threadPoolStart(pThreadpool_t pthreadpool){
if(pthreadpool->isStar == false){
for(int index = 0;index < pthreadpool->threadNums;++index){
pthread_create(&pthreadpool->pThid[index],NULL,threadFunc,pthreadpool);
}
}
pthreadpool->isStar = true;
}
第三步:初始化任务队列,和任务队列的相关操作
void queInit(pQue_t pQue){
memset(&pQue,0,sizeof(que_t));
pthread_mutex_init(&pQue->mutex,NULL);
pthread_cond_init(&pQue->cond,NULL);
pQue->size = 0;
pQue->pHead = NULL;
pQue->pTail = NULL;
}
void queInsert(pQue_t pQue,pNode_t pNew){
if(pQue->pHead == NULL){
pQue->pHead = pNew;
pQue->pTail = pNew;
}else{
pQue->pTail->pNext = pNew;
pQue->pTail = pNew;
}
++pQue->size;
}
int queGet(pQue_t pQue,pNode_t* pGet){
if(0 == pQue->size){
return -1;
}
*pGet = pQue->pHead;
pQue->pHead = pQue->pHead->pNext;
if(NULL == pQue->pHead){
pQue->pTail = NULL;
}
pQue->size--;
return 1;
}
第四步:建立tcp连接
int tcpInit(int* socketFd,char* ip,char* port){
int listenFd = socket(AF_INET,SOCK_STREAM,0);
if(listenFd < 0){
perror("socket");
}
int reuse = 1;
int ret = setsockopt(listenFd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse));
if(ret < 0){
perror("setsockopt");
}
struct sockaddr_in serAddr;
memset(&serAddr,0,sizeof(serAddr));
serAddr.sin_family = AF_INET;
serAddr.sin_addr.s_addr = inet_addr(ip);
serAddr.sin_port = htons(atoi(port));
ret = bind(listenFd,(struct sockaddr*)&serAddr,sizeof(serAddr));
if(ret< 0){
perror("setsockopt");
}
ret = listen(listenFd,10);
*socketFd = listenFd;
return *socketFd;
}
第五步:epoll监听套接字
int epollAdd(int epollfd,int listenfd){
struct epoll_event event;
memset(&event,0,sizeof(event));
event.data.fd = listenfd;
event.events = EPOLLIN;
int ret = epoll_ctl(epollfd,EPOLL_CTL_ADD,listenfd,&event);
if(ret< 0){
perror("epoll_ctl");
}
return 0;
}
第六步:定义工作函数,处理客户端的具体工作
void* threadFunc(void* pArg){
pThreadpool_t pPool = (pThreadpool_t)pArg;
int getSucess = 0;
pNode_t pCur = NULL;
while(1){
pthread_mutex_lock(&pPool->que.mutex);
if(0 == pPool->que.size){
printf("child wait\n");
pthread_cond_wait(&pPool->que.cond,&pPool->que.mutex);
printf("child wake up\n");
}
getSucess = queGet(&pPool->que,&pCur);
pthread_mutex_unlock(&pPool->que.mutex);
if(getSucess != -1){
transfile(pCur->client);
close(pCur->client);
}
}
}
void transfile(int clientfd){
int fd = open(FILENAME,O_RDWR);
if(fd == -1){
perror("open FILENAME is false");
}
int ret = 0;
train_t train;
int headLen = sizeof(train.dataLen);
memset(&train.buf,0,sizeof(train.buf));
strcpy(train.buf,FILENAME);
train.dataLen = sizeof(FILENAME);
ret = send(clientfd,&train,headLen+train.dataLen,0);
if(ret < 0) {
perror("headLen send is false!");
}
struct stat filestat;
memset(&filestat,0,sizeof(filestat));
ret = fstat(fd,&filestat);
if(ret == -1){
perror("fstat is false!");
}
memcpy(train.buf,&filestat.st_size,sizeof(filestat.st_size));
train.dataLen = sizeof(filestat.st_size);
ret = send(clientfd,&train,headLen+train.dataLen,0);
char* pMap = (char*)mmap(NULL,filestat.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(pMap == (char*)-1){
perror("mmap is false");
}
ret = send(clientfd,pMap,filestat.st_size,0);
munmap(pMap,filestat.st_size);
close(fd);
}