Liunx C 线程池模型:实现多线程并发传输文件服务 2.0

源代码如下:
server端
head.h

#ifndef __HEAD_H__
#define __HEAD_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/time.h>
#include <strings.h>
#include <syslog.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/epoll.h>
#include <sys/uio.h>
#include <sys/sendfile.h>
#define ARGS_CHECK(argc,val) {if(argc!=val)  {printf("error args\n");return -1;}}
#define ERROR_CHECK(ret,retVal,funcName) {if(ret==retVal) {perror(funcName);return -1;}}
#define THREAD_ERROR_CHECK(ret,funcName) {if(ret!=0) {printf("%s:%s\n",funcName,strerror(ret));return -1;}}
#define CHILD_THREAD_ERROR_CHECK(ret,funcName) {if(ret!=0) {printf("%s:%s\n",funcName,strerror(ret));return (void*)-1;}}
#endif

tcp_init.c

#include "head.h"

int tcpInit(int *sfd,char* ip,char* port)
{
    int socketFd=socket(AF_INET,SOCK_STREAM,0);
    ERROR_CHECK(socketFd,-1,"socket");
    struct sockaddr_in serAddr;
    bzero(&serAddr,sizeof(serAddr));
    serAddr.sin_family=AF_INET;
    serAddr.sin_port=htons(atoi(port));
    serAddr.sin_addr.s_addr=inet_addr(ip);
    int reuse=1;
    int ret;
    ret=setsockopt(socketFd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(int));
    ERROR_CHECK(ret,-1,"setsockopt");
    ret=bind(socketFd,(struct sockaddr*)&serAddr,sizeof(serAddr));
    ERROR_CHECK(ret,-1,"bind");
    listen(socketFd,10);
    *sfd=socketFd;
    return 0;
}

work_que.h

#ifndef __WORK_QUE_H__
#define __WORK_QUE_H__
#include "head.h"

typedef struct tag_node{
    int newFd;
    struct tag_node* pNext;
}Node_t,*pNode_t;

typedef struct{
    pNode_t queHead,queTail;
    int queCapacity;//队列最大长度
    int queSize;//队列当前长度
    pthread_mutex_t mutex;//队列锁
}Que_t,*pQue_t;

void queInit(pQue_t,int);
void queInsert(pQue_t,pNode_t);
int queGet(pQue_t,pNode_t*);
#endif

work_que.c

#include "work_que.h"

//初始化队列
//设置参数,初始化锁
void queInit(pQue_t pq,int capacity)
{
    bzero(pq,sizeof(Que_t));
    pq->queCapacity=capacity;
    pthread_mutex_init(&pq->mutex,NULL);
    return; 
}

//插入到队列
void queInsert(pQue_t pq,pNode_t pNew)
{
    if(NULL==pq->queHead)
    {
        pq->queHead=pNew;
        pq->queTail=pNew;
    }else{
        pq->queTail->pNext=pNew;
        pq->queTail=pNew;
    }
    pq->queSize++;
}

//从队列中取任务出来
int queGet(pQue_t pq,pNode_t *pDel)
{
    if(NULL==pq->queHead)
    {
        return -1;
    }
    *pDel=pq->queHead;
    pq->queHead=pq->queHead->pNext;
    if(NULL==pq->queHead)
    {
        pq->queTail=NULL;
    }
    pq->queSize--;
    return 0;
}

factory.h

#ifndef __FACTORY_H__
#define __FACTORY_H__
#include "head.h"
#include "work_que.h"

typedef struct{
    Que_t que;    //保存任务的队列
    pthread_cond_t cond;//条件变量,用来唤醒等待的子线程
    pthread_t *pthid;//存储线程ID的起始地址
    int threadNum;//线程数目
    short startFlag;//线程池是否启动
}Factory_t,*pFactory_t;
int factoryInit(pFactory_t,int,int);
int factoryStart(pFactory_t);
int tcpInit(int *sfd,char* ip,char* port);
int tranFile(int newFd);
#endif

factory.c

#include "factory.h"

void cleanupFunc(void* pArg)
{
    pQue_t pq=(pQue_t)pArg;
    printf("thread unlock\n");
    pthread_mutex_unlock(&pq->mutex);
}

//线程函数
void* threadFunc(void* p)
{
    pFactory_t pThreadInfo=(pFactory_t)p;

    //任务队列
    pQue_t pq=&pThreadInfo->que;
    pthread_cleanup_push(cleanupFunc,pq);
    pNode_t pGet;
    int getTaskSuccess;
    //每次去队列中拿任务,先加锁,如果队列为空,在条件变量上等待
    //如果不为空,就拿一个任务,解锁,传输文件
    while(1)
    {
        //退出方式,当startFlag为0时,退出
        if(pThreadInfo->startFlag == 0)
        {
            printf("thread exit\n");
            pthread_exit(NULL);
        }
        pthread_mutex_lock(&pq->mutex);
        if(!pq->queSize)
        {
            pthread_cond_wait(&pThreadInfo->cond,&pq->mutex);
        }

        getTaskSuccess=queGet(pq,&pGet);//拿任务
        pthread_mutex_unlock(&pq->mutex);
        if(!getTaskSuccess)
        {
            tranFile(pGet->newFd);
            free(pGet);
            pGet=NULL;
        }
    }
    pthread_cleanup_pop(1);
}
//初始化线程池,初始化队列,初始化条件变量和锁
//设置线程数量和启动状态。
int factoryInit(pFactory_t p,int threadNum,int capacity)
{
    queInit(&p->que,capacity);
    pthread_cond_init(&p->cond,NULL);
    p->pthid=(pthread_t*)calloc(threadNum,sizeof(pthread_t));
    p->threadNum=threadNum;
    p->startFlag=0;
    return 0;
}

//启动线程池
//按照线程数量创建线程,同时标记为启动状态
int factoryStart(pFactory_t p)
{
    if(!p->startFlag)
    {
        int i;
        p->startFlag=1;
        for(i=0;i<p->threadNum;i++)
        {
            pthread_create(p->pthid+i,NULL,threadFunc,p);
        }
    }
    return 0;
}

tran_file.c

#include "head.h" 
typedef struct{
    int dataLen;
    char buf[1000];
}train_t;
#define FILENAME "file"
int tranFile(int newFd)
{
    train_t train;
    int ret;
    train.dataLen=strlen(FILENAME);//发送文件名
    strcpy(train.buf,FILENAME);
    send(newFd,&train,4+train.dataLen,0);
    //发送文件大小给客户端
    struct stat buf;
    int fd=open(FILENAME,O_RDWR);
    fstat(fd,&buf);
    train.dataLen=sizeof(buf.st_size);
    memcpy(train.buf,&buf.st_size,train.dataLen);
    send(newFd,&train,4+train.dataLen,0);
    //发送文件内容
    ret=sendfile(newFd,fd,NULL,buf.st_size); 
    /* printf("sendfile ret=%d\n",ret); */
    ERROR_CHECK(ret,-1,"sendfile");
    return 0;
}

main.c

#include "factory.h"

int exitFds[2];

void sigFunc(int signum)
{
    printf("ready to exit\n");
    write(exitFds[1],&signum,1);
}

// 传参 ip 端口 线程数量 能力
int main(int argc,char* argv[])
{
    if(argc!=5)
    {
        printf("./thread_pool_server IP PORT THREAD_NUM CAPACITY\n");
        return -1;
    }
    pipe(exitFds);
    //创建子进程,子进程实现线程池
    if(fork())
    {
        //父进程,注释信号处理函数,收到信号后,通知子进程退出
        signal(SIGUSR1,sigFunc);        
        wait(NULL);
        printf("thread pool exit\n");
        exit(0);
    }
    //子进程实现线程池
    // 初始化线程池结构体
    Factory_t threadInfo;
    int threadNum=atoi(argv[3]);
    int capacity=atoi(argv[4]);
    //初始化线程池
    factoryInit(&threadInfo,threadNum,capacity);
    //启动线程池
    factoryStart(&threadInfo);
    int socketFd;
    tcpInit(&socketFd,argv[1],argv[2]);
    int newFd;
    pQue_t pq=&threadInfo.que;
    pNode_t pNew;

    int epfd = epoll_create(1);
    struct epoll_event event,evs[2];
    event.data.fd = socketFd;
    event.events = EPOLLIN;
    int ret = epoll_ctl(epfd,EPOLL_CTL_ADD,socketFd,&event);
    ERROR_CHECK(ret,-1,"epoll_ctl");

    event.data.fd = exitFds[0];
    event.events = EPOLLIN;
    ret = epoll_ctl(epfd,EPOLL_CTL_ADD,exitFds[0],&event);
    ERROR_CHECK(ret,-1,"epoll_ctl");
    int readyFdNum = 0;
    while(1)
    {
        readyFdNum = epoll_wait(epfd,evs,2,-1);
        if(readyFdNum>0)
        {
            for(int i=0;i<readyFdNum;i++)
            {
                if(evs[i].data.fd == socketFd)
                {
                    //接收客户端连接,放到新的节点里,添加到队列中
                    newFd=accept(socketFd,NULL,NULL);
                    pNew=(pNode_t)calloc(1,sizeof(Node_t));
                    pNew->newFd=newFd;
                    //加锁,再去放任务
                    pthread_mutex_lock(&pq->mutex);
                    queInsert(pq,pNew);//放任务
                    pthread_cond_signal(&threadInfo.cond);//唤醒子线程
                    pthread_mutex_unlock(&pq->mutex);
                }

                else if(evs[i].data.fd == exitFds[0])
                {
                    //管道读端可读,表示要退出了
                    //第一种退出方式,轮流给子线程发pthread_cancel信号
                    //子线程收到cancel信号,运行到calcel点,退出,
                    //清理函数中释放锁
                    /* for(int j=0;j<threadInfo.threadNum;j++) */
                    /* { */
                    /*     pthread_cancel(threadInfo.pthid[j]); */
                    /* } */

                    //第二种退出方式,把启动状态标记为0,
                    //子线程完成任务后来判断启动状态,
                    //如果是0,表示要退出了,pthread_exit退出
                    threadInfo.startFlag=0;
                    //把所有等待在条件变量上的子线程唤醒
                    pthread_cond_broadcast(&threadInfo.cond);

                    for(int j=0;j<threadInfo.threadNum;j++)
                    {
                        pthread_join(threadInfo.pthid[j],NULL);
                    }

                    printf("main thread exit\n");
                    exit(0);
                }
            }
        }
    }
    return 0;
}

Makefile

SRCS:=$(wildcard *.c)
OBJS:=$(patsubst %.c,%.o,$(SRCS))
ELF:=thread_pool_server
CC:=gcc
CFLAGS:=-Wall
$(ELF):$(OBJS)
	gcc -o $@ $^ -pthread
clean:
	rm -rf $(OBJS) $(ELF)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值