线程池:服务器端
/******head.h******/
#ifndef __FUNC_H__
#define __FUNC_H__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#endif
/*****work_que.h*****/
#ifndef __WOEK_QUE_H__
#define __WOEK_QUE_H__
#include "head.h"
typedef struct node{ //队列的节点
int new_fd; //主线程接收到新的请求产生一个new_fd,放到队列中
struct node* pnext;
}Node,*pNode
typedef struct{
pNode phead,ptail; //队列的头尾指针
pthread_mutex_t mutex;
//队列包含一个锁,要求互斥地访问队列
int size; //当前队列中元素个数
}que_t,*pque_t;
void que_init(pque_t);
void que_insert(pque_t,int);
void que_get(pque_t,int*);
#endif
/******factory.h*******/
#ifndef __FACTORY_H__
#define __FACTORY_H__
#include "head.h"
#include "work_que.h"
#define FILENAME "file"
typedef void* (*
pfunc)(void*);
//定义一个pfunc类型。这是一个函数指针类型。
typedef struct{
//工厂结构体
pthread_t*
thread;
//num个线程ID的首地址
int
th_num;
//要创建多少个线程
pthread_cond_t
cond;
//条件变量,用于线程之间的同步
int
capacity;
//最多同时有多少个请求
que_t
que;
//工厂有一个队列
pfunc
func_sendfile;
//线程函数指针
int
flag;
//标记,避免工厂启动多次
}factory,*pf;
typedef struct{
//小火车数据类型
int len;
char buf[1000];
}data,*pdata;
void factory_init(pf,int,int,pfunc);
//工厂数据结构初始化
void factory_start(pf);
//工厂启动
void* child_thread(void*);
#endif
/*****send_file.c*****/
#include "head.h"
void
send_n(int new_fd,char* buf,int len){
int ret;
int total=0;
while(total
ret=send(new_fd,buf+total,len-total,0);
total=total+ret;
}
}
void
recv_n(int new_fd,char* buf,int len){
int ret;
int total=0;
while(total
ret=recv(new_fd,buf+total,len-total,0);
total=total+ret;
}
}
void
send_file(int fdw){
data d;
memset(&d,0,sizeof(d));
d.len=strlen(FILENAME);
strcpy(d.buf,FILENAME);
int ret;
ret=send(fdw,&d,4+d.len,0); //发送文件名
if(-1==ret){
perror("send");
exit(-1);
}
int fd=open(FILENAME,O_RDONLY);
if(-1==fd){
perror("open");
exit(-1);
}
while(memset(&d,0,sizeof(d)),(d.len=read(fd,d.buf,sizeof(d.buf)))>0){
send_n(fdw,&d,4+d.len);
}
ret=0;
send_n(fdw,&ret,sizeof(int)); //发送文件结束标志
close(fdw);
}
work_que.c
#include "work_que.h"
void
que_init(pque_t pq){
//初始化队列
pq->phead=NULL;
pq->ptail=NULL;
pthread_mutex_init(&pq->mutex,NULL);
//初始化队列的锁
pq->size=0;
}
void
que_insert(pque_t pq,int fd){
//把新产生的fd放到队列中
pNode pnew=(pNode)calloc(1,sizeof(Node));
//新建一个节点,存放fd
pnew->new_fd=fd;
pthread_mutex_lock(&pq->mutex); //互斥地访问队列
if(pq->phead==NULL){
//采用尾插法,插入新的节点
pq->phead=pnew;
pq->ptail=pnew;
}else{
pq->ptail->pnext=pnew;
pq->ptail=pnew;
}
(pq->size)++;
pthread_mutex_unlock(&pq->mutex);
}
void
que_get(pque_t pq,int* fd){
//取出一个new_fd
pNode pcur;
pcur=pq->phead;
*fd=pcur->new_fd; //把队首的元素取出来
pq->phead=pcur->pnext;
free(pcur); //尽量把malloc和free放到锁外面
if(pq->phead == NULL){
pq->ptail=NULL;
}
(pq->size)--;
pcur=NULL;
//防止产生野指针
}
/*****factory.c*****/
#include "factory.h"
void
factory_init(pf p,int
num,int cap,pfunc
func_sendfile){
//初始化工厂:num为要创建的线程数,cap是同时请求的最大数目,func_sendfile 是一个函数指针类型的变量。所以func_sendfile等于child_thread,指向子线程
p->thread=(pthread_t*)
calloc(num,sizeof(pthread_t));
//num个线程ID的首地址.pthread_t pth_id[num].因为num变化,所以calloc。
p->th_num=num;
//要创建的线程数
pthread_cond_init(&p->cond,NULL); //条件变量初始化
p->capacity=cap;
//最多同时有多少个请求
que_init(&p->que);
//初始化队列。因为要改变队列的值,所以传地址
p->func_sendfile=func_sendfile;
//p->func_sendfile也是函数指针类型。所以p->func_sendfile等于child_thread
p->flag=0;
}
void
factory_start(pf p){
//工厂启动。p是factory * 类型
int i;
if(
p->flag ==0){
//如果工厂未被启动
for(i=0;i
pthread_create(&
p->thread[i],NULL,
p->func_sendfile,(void*)p);
//创建p->th_num个子线程。并把p作为参数传递给子线程
}
}
p->flag=1;
//标记工厂已经被启动
}
/*****main.c*******/
#include "factory.h"
void* child_thread(void* p){
pf p1=(pf)p;
int new_fd;
while(1){
pthread_mutex_lock(&p1->que.mutex); //互斥地访问队列
if(p1->que.size==0){
//如果进程中没有new_fd,就等待被唤醒
pthread_cond_wait(&p1->cond,&p1->que.mutex);
}
que_get(&p1->que,&new_fd);
//取出一个new_fd,返回给new_fd
pthread_mutex_unlock(&p1->que.mutex);
send_file(new_fd);
//发送文件。同进程池的send_file函数
}
}
int main(int argc,char* argv[]){
//参数:IP地址 端口 创建的线程数 capacity
if(argc!=5){
printf("error args\n");
return -1;
}
int
num=atoi(argv[3]); //要创建的线程数
int
cap=atoi(argv[4]); //容量,最多多少个线程连接
factory f;
factory_init(&f,num,cap,child_thread);
//初始化工厂。child_thread是函数的地址(函数指针类型)。
factory_start(&f);
//工厂启动:创建num个子线程。
int sfd=
socket(AF_INET,SOCK_STREAM,0);
if(-1==sfd){
perror("socket");
return -1;
}
struct sockaddr_in
ser;
memset(&ser,0,sizeof(ser));
ser.sin_family=AF_INET;
ser.sin_port=htons(atoi(argv[2]));//一定要用htons
ser.sin_addr.s_addr=inet_addr(argv[1]);
int ret;
ret=
bind(sfd,(struct sockaddr*)&ser,sizeof(struct sockaddr));
if(-1==ret){
perror("bind");
return -1;
}
listen(sfd,
cap);
//最大可接受的请求的数量,即队列中最多有多少个new_fd
int new_fd;
while(1){
new_fd=
accept(sfd,NULL,NULL);
if(-1==new_fd){
perror("accept");
return -1;
}
que_insert(&f.que,new_fd);
//把新产生的new_fd放到队列中
pthread_cond_signal(&f.cond);
//唤醒一个子进程
}
}
|
//客户端:与进程池客户端完全相同
#include "func.h"
void send_n(int new_fd,char* buf,int len){
int ret;
int total=0;
while(total
ret=send(new_fd,buf+total,len-total,0);
total=total+ret;
}
}
void recv_n(int new_fd,char* buf,int len){
int ret;
int total=0;
while(total
ret=recv(new_fd,buf+total,len-total,0);
total=total+ret;
}
}
int main(int argc,char** argv){
//传入参数:IP地址、端口
if(argc !=3){
printf("error args\n");
return -1;
}
int sfd=
socket(AF_INET,SOCK_STREAM,0);
if(-1==sfd){
perror("socket");
return -1;
}
struct sockaddr_in
ser;
memset(&ser,0,sizeof(ser));
ser.sin_family=AF_INET;
ser.sin_port=htons(atoi(argv[2]));
ser.sin_addr.s_addr=inet_addr(argv[1]);
int ret;
ret=
connect(sfd,(struct sockaddr*)&ser,sizeof(struct sockaddr));
if(-1==ret){
perror("connect");
return -1;
}
data d;
//定义小火车结构体
memset(&d,0,sizeof(d));
recv_n(sfd,&d.len,sizeof(int));
//读取要接收文件名字的长度
recv_n(sfd,d.buf,d.len);
//读取文件名
int fd;
fd=open(d.buf,O_RDWR|O_CREAT,0666);
//在本地创建文件
if(-1==fd){
perror("open");
return -1;
}
while(1){
memset(&d,0,sizeof(d));
recv_n(sfd,&d.len,sizeof(int));
//接收小火车头
if(d.len >0){
//如果后面有数据
recv_n(sfd,d.buf,d.len);
//读出buf的长度。一定要保证读出len的长度,而不能读少了。
write(fd,d.buf,d.len);
//读完之后写到文件中。
}else{
//如果只有火车头,后面没有数据,说明文件已经下载完了
break;
}
}
close(sfd);
close(fd);
return 0;
}
|