1 Server端与Client端公用的代码库:包含 tcp.h,tcp.c , file.h, file.c , tpool.h, tpool.c
//tcp.h 头文件
#ifndef TCP_H_
#define TCP_H_
#include<stdio.h>
#include<stdlib.h> /*exit()*/
#include<sys/socket.h> /*bind(),socket()...*/
#include<arpa/inet.h> /*inet_aton(),inet_ntoa(),inet_pton()...*/
#include<netinet/in.h> /* struct sockaddr_in, htons() ...*/
#include<string.h> /*bzero()*/
#include<unistd.h> /* read(),write(),fork()*/
#include<errno.h> /*errno*/
#include<signal.h>
#include<sys/wait.h>
#include<fcntl.h> /*open(),creat()*/
#include<sys/select.h>
#include<sys/time.h>
#include<sys/stat.h> /* mkdir*/
// #include <stdio.h>
// #include <stdlib.h>
// #include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <assert.h>
#define MAXLINE 4096
#define PORT 9887
#define REMOTE_IP "127.0.0.1"
#define LISTENQ 1024
#define MAX 256
#define PATH "./tmp"
#define PATH2 "./tmp/\0"
#define SA struct sockaddr
#define max(a,b) ((a)>(b)?(a):(b))
typedef void Sigfunc(int);
#endif
// tcp.c tcp 读写函数,readn, writen
#include "tcp.h"
Sigfunc *Signal(int sig,Sigfunc *func)
{
struct sigaction act,oact; /* storage size is unknow, why???*/
act.sa_handler=func;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
if(sig==SIGALRM)
{
#ifdef SA_INTERRUPT
act.sa_flags|=SA_INTERRUPT;
#endif
}
else
{
#ifdef SA_RESTART
act.sa_flags|=SA_RESTART;
#endif
}
if(sigaction(sig,&act,&oact)<0)
return(SIG_ERR);
return(oact.sa_handler);
}
ssize_t /* Read "n" bytes from a descriptor. */
readn(int fd, void *vptr, size_t n) /* <sys/uio.h> the same below*/
{
size_t nleft;
ssize_t nread;
char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nread = read(fd, ptr, nleft)) < 0) {
if (errno == EINTR)
nread = 0; /* and call read() again */
else
return(-1);
} else if (nread == 0)
break; /* EOF */
nleft -= nread;
ptr += nread;
}
return(n - nleft); /* return >= 0 */
}
ssize_t writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
if (nwritten < 0 && errno == EINTR)
nwritten = 0; /* and call write() again */
else
return(-1); /* error */
}
nleft -= nwritten;
ptr += nwritten;
}
return(n);
}
// fil.h 文件传输格式
#ifndef FILE_H_
#define FILE_H_
/* 处理上传单个文件的功能*/
/*
#define SEND_FILE "SEND_FILE"
#define REQ_FILE "REQU_FILE"
#define READY_OK "REDY_OK"
#define SEND_FIN "SEND_FIN"
#define RESP_FIN "RESP_FIN"
*/
#define CMD_LEN 6
#define REC_OK "REC_OK" /*接收成功*/
#define REC_FAIL "R_FAIL"/* 接受失败*/
#define FD_NOT_SET '0'
#define FD_OK '1'
#define SUCCESS 1
#define FAILED 0
typedef struct net_file
{
unsigned int filename_size;
char filename[MAX];
unsigned long filedata_size;
int fd;
char fd_stat;
char buf[MAXLINE];
// unsigned char mark;
// struct net_file *next;
}netfile_t;
#endif
// file.c
#include "tcp.h"
#include "file.h"
/* filename:end with '\0' */
int receive_net_file(int sockfd,netfile_t *netfile)
{
int read_bytes=0;
int nready=0;
char buf[MAXLINE];
char path[256];
if(netfile==NULL)
return FAILED;
bzero(netfile,sizeof(netfile_t));
/*reveive file_name_size */
if(readn(sockfd,&netfile->filename_size,sizeof(unsigned int))==0) /* character sequence ?????*/
{
printf("client exit 1 \n");
return FAILED;
}
printf("file_name_size:%u\n",netfile->filename_size);
if(readn(sockfd,netfile->filename,netfile->filename_size)==0)
{
printf("client exit 2 \n");
return FAILED;
}
netfile->filename[netfile->filename_size]='\0';
printf("filename:%s \n",netfile->filename);
if(readn(sockfd,&netfile->filedata_size,sizeof(unsigned long))==0)
{
printf("client exit 3\n");
return FAILED;
}
printf("filedata_size:%lu \n",netfile->filedata_size);
/* creat a file */
strcpy(path,PATH2);
strcat(path,netfile->filename);
printf("path:%s\n",path);
if((netfile->fd=open(path,O_RDWR|O_CREAT|O_TRUNC,0644))==-1)
{
perror("creat file fialed:");
netfile->fd_stat=FD_NOT_SET;
writen(sockfd,REC_FAIL,CMD_LEN); /*返回失败信息*/
return FAILED;
}
/* no data ******/
// if(netfile->filedata_size==0){
// close(netfile->fd);
// netfile->fd_stat=FD_NOT_SET;
// return -1;
// }
netfile->fd_stat=FD_OK;
while(read_bytes<netfile->filedata_size)
{
bzero(buf,MAXLINE);
if(netfile->filedata_size-read_bytes>MAXLINE)
nready=readn(sockfd,buf,MAXLINE);
else /* 最后不够maxline 整数的字节*/
nready=readn(sockfd,buf,netfile->filedata_size-read_bytes);
if(nready!=write(netfile->fd,buf,nready)) /*写入文件*/
{
printf("error\n");
writen(sockfd,REC_FAIL,CMD_LEN);
return FAILED;
}
read_bytes+=MAXLINE;
}
writen(sockfd,REC_OK,CMD_LEN);
netfile->fd_stat=FD_NOT_SET;
close(netfile->fd);
return SUCCESS;
}
void close_net_file(netfile_t *netfile)
{
if(netfile==NULL)
return;
if(netfile->fd_stat==FD_OK)
{
netfile->fd_stat=FD_NOT_SET;
close(netfile->fd);
}
}
// tpool.h 线程池
ifndef TPOOL_H_
#define TPOOL_H_
#define BUSY_THRESHOLD 0.5 //(busy thread)/(all thread threshold)
#define MANAGE_INTERVAL 5 //tp manage thread sleep interval
typedef struct worker
{
void *(*process) (void *arg);
void *arg; /* connection socket */
struct worker *next;
}CThread_worker;
typedef struct thread_info
{
pthread_t threadid;
int busy;/* 1 is busy,0 is idle */
}thread_info_t;
/*threadpool structure */
typedef struct
{
pthread_mutex_t queue_lock;
pthread_cond_t queue_ready;
CThread_worker *queue_head; /* all tasks which are waiting */
int shutdown; /* whether destroy the CThread_pool */
thread_info_t *thread_queue; /*thread queue */
pthread_t manage_thread_id;
int min_thread_num; /* minmum number of threads */
int max_thread_num; /* maxnum number of threads */
int cur_thread_num;
int cur_queue_size; /* thread's number in the waiting-queue */
} CThread_pool;
#endif
// tpool.c
#include "tcp.h"
#include "tpool.h"
/*
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <assert.h>
*/
int pool_add_worker (void *(*process) (void *arg), void *arg);
void *thread_routine (void *arg);
int delete_thread();
int get_id_by_threadid( int threadid);
int get_tp_status();
void *manage_routine(void *arg);
static CThread_pool *pool = NULL;
void pool_init (int min_thread_num,int max_thread_num)
{
pool = (CThread_pool *) malloc (sizeof (CThread_pool));
pthread_mutex_init (&(pool->queue_lock), NULL);
pthread_cond_init (&(pool->queue_ready), NULL);
pool->queue_head = NULL;
pool->max_thread_num = max_thread_num;
pool->cur_queue_size = 0;
pool->cur_thread_num=min_thread_num;
pool->min_thread_num=min_thread_num;
pool->shutdown = 0;
pool->thread_queue = (thread_info_t *) malloc (max_thread_num * sizeof (thread_info_t));
int i = 0;
for (i = 0; i < min_thread_num; i++)
{
pthread_create(&(pool->thread_queue[i].threadid), NULL, thread_routine, NULL);
pool->thread_queue[i].busy=0;
}
pthread_create(&(pool->manage_thread_id),NULL, manage_routine, NULL);
}
int add_thread()
{
// pthread_mutex_lock (&(pool->queue_lock));
if(pool->cur_thread_num<pool->max_thread_num)
{
printf("**********pool->cur_thread_num:%d\n",pool->cur_thread_num);
// pthread_mutex_unlock (&(pool->queue_lock));
pool->thread_queue[pool->cur_thread_num].busy=0;
pool->cur_thread_num++;
pthread_create (&(pool->thread_queue[pool->cur_thread_num].threadid), NULL, thread_routine, NULL);
printf ("thread %lu is added\n", pool->thread_queue[pool->cur_thread_num].threadid);
return 1;
}
// else
// pthread_mutex_unlock (&(pool->queue_lock));
return 0;
}
int delete_thread(){
int i;
// pthread_mutex_lock (&(pool->queue_lock));
//current thread num can't < min thread num or if last thread is busy, do nothing
if(pool->cur_thread_num <= pool->min_thread_num)
{
// pthread_mutex_unlock (&(pool->queue_lock));
return 0;
}
for(i=0;pool->thread_queue[i].busy!=0 && i<pool->cur_thread_num;i++){};
if(i<pool->cur_thread_num)
{
// kill(pool->thread_queue[i].threadid, SIGKILL);
pthread_join (pool->thread_queue[i].threadid, NULL);
printf ("thread %lu is Killed\n", pool->thread_queue[i].threadid);
}
pool->cur_thread_num--;
// pthread_mutex_unlock (&(pool->queue_lock));
return 1;
}
int get_id_by_threadid( int threadid){
int i;
for(i=0;i<pool->cur_thread_num;i++){
if(threadid == pool->thread_queue[i].threadid)
return i;
}
return -1;
}
int get_tp_status(){
float busy_num = 0.0;
int i;
if(pool->cur_thread_num==pool->min_thread_num)
return 1;
//get busy thread number
for(i=0;i<pool->cur_thread_num;i++){
if(pool->thread_queue[i].busy)
busy_num++;
}
//0.2? or other num?
if(busy_num/(pool->cur_thread_num) < BUSY_THRESHOLD)
// if(pool->cur_thread_num>pool->min_thread_num+1)
return 0;//idle status
else
return 1;//busy or normal status
}
int
pool_add_worker (void *(*process) (void *arg), void *arg)
{
/**/
CThread_worker *newworker = (CThread_worker *) malloc (sizeof (CThread_worker));
newworker->process = process;
newworker->arg = arg;
newworker->next = NULL;
pthread_mutex_lock (&(pool->queue_lock));
CThread_worker *member = pool->queue_head;
if (member != NULL) /* add member to the end of the pool*/
{
while (member->next != NULL)
member = member->next;
member->next = newworker;
}
else
{
pool->queue_head = newworker;
}
assert (pool->queue_head != NULL);
pool->cur_queue_size++;
pthread_mutex_unlock (&(pool->queue_lock));
pthread_cond_signal (&(pool->queue_ready));
return 0;
}
int pool_destroy ()
{
if (pool->shutdown)
return -1;
pool->shutdown = 1;
pthread_cond_broadcast (&(pool->queue_ready));
int i;
for (i = 0; i < pool->cur_thread_num; i++)
pthread_join (pool->thread_queue[i].threadid, NULL);
free (pool->thread_queue);
pthread_join (pool->manage_thread_id, NULL);
CThread_worker *head = NULL;
while (pool->queue_head != NULL)
{
head = pool->queue_head;
pool->queue_head = pool->queue_head->next;
free (head);
}
pthread_mutex_destroy(&(pool->queue_lock));
pthread_cond_destroy(&(pool->queue_ready));
free (pool);
pool=NULL;
return 0;
}
void * thread_routine (void *arg)
{
printf ("starting thread %lu\n", pthread_self ());
while (1)
{
pthread_mutex_lock (&(pool->queue_lock));
/**/
while (pool->cur_queue_size == 0 && !pool->shutdown)
{
printf ("thread %lu is waiting\n", pthread_self ());
pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock));
}
if (pool->shutdown)
{
/*force to kill*/
pthread_mutex_unlock (&(pool->queue_lock));
printf ("thread %lu will exit\n", pthread_self ());
pthread_exit (NULL);
}
printf ("thread %lu is starting to work\n", pthread_self ());
/**/
assert (pool->cur_queue_size != 0);
assert (pool->queue_head != NULL);
/**/
CThread_worker *worker = pool->queue_head;
pool->queue_head = worker->next;
pool->cur_queue_size--;
// pool->cur_thread_num++;
pool->thread_queue[get_id_by_threadid(pthread_self ())].busy=1;/* lock ??**/
pthread_mutex_unlock (&(pool->queue_lock));
/**/
(*(worker->process)) (worker->arg);
/* after processing */
pthread_mutex_lock (&(pool->queue_lock));
pool->thread_queue[get_id_by_threadid(pthread_self ())].busy=0;
// pool->cur_thread_num--;
pthread_mutex_unlock (&(pool->queue_lock));
free (worker);
worker = NULL;
}
/**/
pthread_exit (NULL);
}
void *manage_routine(void *arg){
int i;
printf ("manage_thread %lu is starting to work\n", pthread_self ());
sleep(MANAGE_INTERVAL);
do{
//
for(i=0;pool->thread_queue[i].busy!=0 && i<pool->cur_thread_num;i++){};
pthread_mutex_lock (&(pool->queue_lock));
if(i==pool->cur_thread_num && pool->cur_queue_size>0)
{
pthread_mutex_unlock (&(pool->queue_lock));
add_thread();
}
else
pthread_mutex_unlock (&(pool->queue_lock));
sleep(MANAGE_INTERVAL);
if(get_tp_status() == 0 ){
do{
if( !delete_thread() )
break;
}while(1);
}
}while(1);
}
2 Server端
server.c
#include "tcp.h"
#include "file.h"
/* using sigle process and the function--select() */
/* existed question:denial-of-service */
void * myprocess (void *arg)
{
int sockfd=*(int *)arg;
netfile_t *netfile;
netfile=(netfile_t*)malloc(sizeof(netfile_t));
while(1)
{
if(receive_net_file(sockfd,netfile)==FAILED)
{
break;
}
printf("Receiving file:%s is finished \n",netfile->filename);
close_net_file(netfile);
}
free(netfile);
}
/*初始化:创建上传后文件存放的文件夹*/
config_Init()
{
if(opendir(PATH)==NULL)
{
if(mkdir(PATH,0755)<0) /*make a directory */
printf("\033[40;31m failed to create a folder \033[0m \n");/* if exist ,it generage a error */
}
else
closedir(PATH);
}
/* select () :detect listen socket,generate a thread */
void Listen ()
{
int listenfd,connfd,maxfd;
fd_set rset,allset;
socklen_t clilen;
char buff[16];
struct sockaddr_in cliaddr,servaddr;
listenfd=socket(AF_INET,SOCK_STREAM,0);
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(PORT);
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
bind(listenfd,(SA*)&servaddr,sizeof(servaddr));
listen(listenfd,LISTENQ);
printf("Server(PORT:%d) is Listening......\n",PORT);
maxfd=listenfd; /*initialize*/
FD_ZERO(&allset);
FD_SET(listenfd,&allset);
for(;;)
{
printf("%s,%d,blocked in select()*****: \n",__FILE__,__LINE__); /*test*/
rset=allset;
select(maxfd+1,&rset,NULL,NULL,NULL); /*detect */
if(FD_ISSET(listenfd,&rset))
{
clilen=sizeof(cliaddr);
connfd=accept(listenfd,(SA*)&cliaddr,&clilen);
printf("********connection from %s,port %d *******\n", /* a successful connection */
inet_ntop(AF_INET,&cliaddr.sin_addr,buff,sizeof(buff)),
ntohs(cliaddr.sin_port));
pool_add_worker (myprocess, &connfd);/* add a connfd */
}
}
}
int main(void)
{
config_Init();
pool_init (3,5); /* the server will generate 10 threads */
Listen();
pool_destroy ();
return 0;
}
makefile 文件
CC = gcc
XX = g++
CFLAGS = -Wall -O -g
TARGET = ./serv
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
SOURCES = $(wildcard *.c )
OBJS = $(patsubst %.c,%.o,$(SOURCES))
$(TARGET) : $(OBJS)
$(CC) $(OBJS) -o $(TARGET) -lpthread
chmod a+x $(TARGET)
clean:
rm -rf *.o
cleanall:
rm -rf *.o serv *~
3 客户端代码
#include "tcp.h"
#include "file.h"
/* 目前只有1 功能*/
void input_files(int sockfd)
{
char fname[MAX];
int i;
char str[MAX];
netfile_t *netfile;
char choice[10];
A:printf("--------------MENU------------------:\n");
printf("Please input your choice:\n");
printf(" 1: upload files, 2: download ,0:exit \n");
printf("------------------------------------:\n");
scanf("%s",choice);
if(strcmp(choice,"1")==0)
{
do
{
printf("Please input filename:\n");
scanf("%s",fname);/* should use fgets()*/
netfile=(netfile_t*)malloc(sizeof(netfile_t));
if(open_net_file(netfile,fname) ==-1)
{
printf("Filename is error,can't open \n");
goto B;
}
if(sendfile(sockfd,netfile)==FAILED)
{
break;
}
close_net_file(netfile);
B:printf("Do you want to transmit another file :(Y or N) \n");
scanf("%s",str) ;
}while(strcmp(str,"Y")==0 || strcmp(str,"y")==0);
free(netfile);
goto A;
}
}
int init()
{
int sockfd;
struct sockaddr_in servaddr;
if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("socket errir");
exit(1);
}
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(PORT);
if(inet_pton(AF_INET,REMOTE_IP,&servaddr.sin_addr)<=0)
{
perror("inet_pton error");
exit(1);
}
/* servaddr.sin_addr.s_addr=inet_addr(REMOTE_IP); *****two methods */
if(connect(sockfd,(SA*)&servaddr,sizeof(servaddr))<0)
{
close(sockfd);
perror("connect error ");
exit(1);
}
return sockfd;
}
int main(int argc,char **argv)
{
input_files(init());
exit(0); /*退出*/
}
makefile 文件
CC = gcc
CFLAGS = -Wall -O -g
TARGET = ./cli
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
SOURCES = $(wildcard *.c )
OBJS = $(patsubst %.c,%.o,$(SOURCES))
$(TARGET) : $(OBJS)
$(CC) $(OBJS) -o $(TARGET)
chmod a+x $(TARGET)
clean:
rm -rf *.o
cleanall:
rm -rf *.o cli *~