源代码如下:
服务器端:
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 <signal.h>
#include <sys/msg.h>
#include <errno.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/epoll.h>
#include <sys/uio.h>
#include <sys/sendfile.h>
#include <fcntl.h>
#include <assert.h>
#include <libgen.h>
#include <stdbool.h>
#define CHILD_THREAD_ERROR_CHECK(ret,funcName){if(ret!=0){printf("%s:%s\n",funcName,strerror(ret));return (void*)-1;}}
#define THREAD_ERROR_CHECK(ret,funcName){if(ret!=0){printf("%s:%s\n",funcName,strerror(ret));return -1;}}
#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;}}
#endif
work_que.h
#ifndef _WORK_QUE_H_
#define _WORK_QUE_H_
#include "head.h"
typedef struct tag_node{ //客户端文件描述符struct
int newFd;
struct tag_node* pNext;
}Node_t,*pNode_t;
typedef struct{ //等待队列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* threadFunc(void* p)
{
pFactory_t pThreadInfo=(pFactory_t)p;
pQue_t pq=&pThreadInfo->que;
pNode_t pGet;
int getTaskSuccess;
while(1)
{
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;
}
}
}
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;
}
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;
}
tran_file.c
#include "head.h"
void sigFunc(int signum)
{
printf("%d is coming\n",signum);
}
typedef struct{
int dataLen;
char buf[1000];
}train_t;
#define FILENAME "file"
int tranFile(int newFd)
{
signal(SIGPIPE,sigFunc);
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");
close(fd);
close(newFd);
return 0;
}
main.c
#include "factory.h"
int main(int argc,char* argv[])
{
if(argc!=5)
{
printf("./thread_pool_server IP PORT THREAD_NUM CAPACITY\n");
return -1;
}
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;
while(1)
{
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_mutex_unlock(&pq->mutex);
pthread_cond_signal(&threadInfo.cond); //唤醒子线程
}
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)
客户端:
#include "head.h"
int recvCycle(int sfd,void* buf,int recvLen) //socketfd
{
char *p=(char*)buf;
int total=0,ret;
while(total<recvLen) //recv返回接收的字节大小
{
ret=recv(sfd,p+total,recvLen-total,0); //下次再次接收数据的时候放在buf的p+total的位置
if(0==ret)
{
return -1;
}
total+=ret; //累加到total上
}
return 0;
}
tcp_client.c
#define _GNU_SOURCE
#include <func.h>
int recvCycle(int,void*,int);
int main(int argc,char* argv[])
{
ARGS_CHECK(argc,3);
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(argv[2]));
serAddr.sin_addr.s_addr=inet_addr(argv[1]);
int ret;
ret=connect(socketFd,(struct sockaddr*)&serAddr,sizeof(serAddr));
ERROR_CHECK(ret,-1,"connect");
int fd;
int dataLen;
char buf[1000]={0};
recvCycle(socketFd,&dataLen,4); //接收文件名的大小,存入dataLen(占多少字节)
recvCycle(socketFd,buf,dataLen); //接收文件名
fd=open(buf,O_CREAT|O_RDWR,0666);//创建文件名,加权限
ERROR_CHECK(fd,-1,"open");
//接收文件大小
off_t fileSize,downLoadSize=0,slice,lastLoadSize=0;
recvCycle(socketFd,&dataLen,4); //长度存入dataLen,比如 400000字节,占4个字节空间
recvCycle(socketFd,&fileSize,dataLen); //实际fileSize的值为40000字节
printf("fileSize=%ld\n",fileSize);
//time_t lastTime, nowTime;
//lastTime=nowTime=time(NULL);
struct timeval start,end;
int fds[2];
pipe(fds);
gettimeofday(&start,NULL);
slice=fileSize/1000;
while(downLoadSize<fileSize)
{
ret=splice(socketFd,NULL,fds[1],NULL,65535,SPLICE_F_MOVE|SPLICE_F_MORE);
ERROR_CHECK(ret,-1,"splice");
splice(fds[0],NULL,fd,NULL,ret,SPLICE_F_MOVE|SPLICE_F_MORE);
downLoadSize+=ret;
if(downLoadSize-lastLoadSize>slice)
{
printf("%5.2f%s\r",(float)downLoadSize/fileSize*100,"%");
fflush(stdout); //每次打印后,情况输出缓冲区
lastLoadSize=downLoadSize;
}
//通过splice函数将socket缓冲区的内容写入到fds[1]中,再从管道的读端fds[0]读出数据写入到用户
//打开的文件描述符。整个过程未执行recv/send操作,因此也未涉及用户空间和内核空间的数据拷贝
}
gettimeofday(&end,NULL);
printf("100.00%%\n");
printf("use time=%ld\n",(end.tv_sec-start.tv_sec)*1000000+end.tv_usec-start.tv_usec);
close(fd);
close(socketFd);
return 0;
}