└── FileTransfer ├── FileTransfer ├── README ├── client ├── Makefile ├── client.c ├── createfile │ ├── create1G │ ├── create512M │ ├── file_ctl.c │ ├── file_ctl.h │ └── file_ctl_test.c ├── tpool.c ├── tpool.h ├── work.c └── work.h ├── server ├── Makefile ├── args ├── server.c ├── shell ├── tpool.c ├── tpool.h ├── work.c └── work.h ├── server架构.jpeg └── 演示.ppt /FileTransfer/FileTransfer: -------------------------------------------------------------------------------- 1 | 2 | # Please enter the commit message for your changes. Lines starting 3 | # with '#' will be ignored, and an empty message aborts the commit. 4 | # 5 | # Committer: hejie 6 | # 7 | # On branch master 8 | # 9 | # Initial commit 10 | # 11 | # Changes to be committed: 12 | # new file: README 13 | # new file: client/Makefile 14 | # new file: client/client.c 15 | # new file: client/createfile/create1G 16 | # new file: client/createfile/create512M 17 | # new file: client/createfile/file_ctl.c 18 | # new file: client/createfile/file_ctl.h 19 | # new file: client/createfile/file_ctl_test.c 20 | # new file: client/tpool.c 21 | # new file: client/tpool.h 22 | # new file: client/work.c 23 | # new file: client/work.h 24 | # new file: server/Makefile 25 | # new file: server/args 26 | # new file: server/server.c 27 | # new file: server/shell 28 | # new file: server/tpool.c 29 | # new file: server/tpool.h 30 | # new file: server/work.c 31 | # new file: server/work.h 32 | # new file: "server\346\236\266\346\236\204.jpeg" 33 | # new file: "\346\274\224\347\244\272.ppt" 34 | # 35 | 36 | -------------------------------------------------------------------------------- /FileTransfer/README: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: README 3 | > Author: HeJie 4 | > Mail: sa614415@mail.ustc.edu.cn 5 | > Created Time: 2015年01月03日 星期五 01时01分39秒 6 | ************************************************************************/ 7 | 8 | Server:EPOLL + 线程池 9 | Client:多线程 10 | 11 | 架构: 12 | Client(多线程) ----------> Server(EPOLL+线程池) 13 | 14 | 1.支持多客户同时上传文件,每个文件由多个线程负责传送 15 | 2.Server可以调节Thread pool大小 16 | 3.每个Client和Server都建立单独的信息交换socket,独立于数据块传送socket,用于交换控制信息,直到文件传输结束 17 | 4.Server支持多种类型,有独立的Server Type字段,用于表示Client传送数据类型(Server以此为判断提供不同服务),可以扩展Server的功能,提供文件服务以外的服务 18 | 5.线程池封装好的,直接可以include头文件,提供三个接口 19 | 6.文件读写使用mmap(), 减少内核态和用户态的切换,加快文件读写速度 20 | 21 | 文件说明: 22 | server/: 23 | tpopl.h、tpool.c:封装的池,预留线程池创建、添加任务、销毁接口 24 | work.h、work.c:包含线程可以执行的任务,支持添加更多的任务 25 | server.c:Server代码,响应client,添加任务 26 | 27 | client/: 28 | 与Server代码类似 29 | -------------------------------------------------------------------------------- /FileTransfer/client/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for Client 3 | # 4 | all: 5 | gcc -o client tpool.c work.c client.c -lpthread 6 | 7 | clean: 8 | rm client 9 | -------------------------------------------------------------------------------- /FileTransfer/client/client.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: clien.c 3 | > Author: HeJie 4 | > Mail: sa614415@mail.ustc.edu.cn 5 | > Created Time: 2015年01月02日 星期五 17时04分28秒 6 | ************************************************************************/ 7 | 8 | #include "tpool.h" 9 | #include "work.h" 10 | 11 | int port=PORT; //默认Port 12 | char *mbegin; //map起始地址 13 | 14 | int main(int argc, char **argv) 15 | { 16 | /*初始化Client*/ 17 | if (argc>1) 18 | port = atoi(argv[1]); 19 | int info_fd = Client_init(SERVER_IP); 20 | 21 | char filename[FILENAME_MAXLEN] = {0}; 22 | printf("BLOCKSIZE= %d\n",BLOCKSIZE); 23 | printf("Input filename : "); 24 | scanf("%s",filename); 25 | int fd=0; 26 | if((fd = open(filename, O_RDWR)) == -1 ) 27 | { 28 | printf("open erro !\n"); 29 | exit(-1); 30 | } 31 | 32 | /*Timer*/ 33 | printf("Timer start!\n"); 34 | time_t t_start, t_end; 35 | t_start=time(NULL); 36 | 37 | /*发送文件信息*/ 38 | struct stat filestat; 39 | fstat(fd ,&filestat); 40 | int last_bs=0; 41 | struct fileinfo finfo; 42 | send_fileinfo(info_fd, filename, &filestat, &finfo, &last_bs); 43 | 44 | /*接收Server分配的ID*/ 45 | char id_buf[INT_SIZE] = {0}; 46 | int n=0; 47 | for(n=0; nfilename, filename); 85 | p_fhead->id = freeid; 86 | p_fhead->offset = offset; 87 | p_fhead->bs = last_bs; 88 | 89 | if (pthread_create(&pid[j], NULL, send_filedata, (void *)p_fhead) != 0){ 90 | printf("%s:pthread_create failed, errno:%d, error:%s\n", __FUNCTION__, errno, strerror(errno)); 91 | exit(-1); 92 | } 93 | } 94 | 95 | /*回收线程*/ 96 | for (j = 0; j < num; ++j) { 97 | pthread_join(pid[j], NULL); 98 | } 99 | 100 | /*计时结束*/ 101 | t_end=time(NULL); 102 | printf("Master prosess exit!\n"); 103 | printf("共用时%.0fs\n",difftime(t_end,t_start)); 104 | 105 | return 0; 106 | } 107 | 108 | -------------------------------------------------------------------------------- /FileTransfer/client/createfile/create1G: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerryos/FileTransfer/168e236826b586d99058a2727dae0c4d4d58b989/FileTransfer/client/createfile/create1G -------------------------------------------------------------------------------- /FileTransfer/client/createfile/create512M: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerryos/FileTransfer/168e236826b586d99058a2727dae0c4d4d58b989/FileTransfer/client/createfile/create512M -------------------------------------------------------------------------------- /FileTransfer/client/createfile/file_ctl.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: file_ctl.c 3 | > Author: HeJie 4 | > Mail: sa614415@mail.ustc.edu.cn 5 | > Created Time: 2015年01月02日 星期五 17时04分28秒 6 | ************************************************************************/ 7 | 8 | #include "file_ctl.h" 9 | 10 | int createfile(char *filename, int size) 11 | { 12 | int fd = open(filename, O_RDWR | O_CREAT); 13 | fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 14 | int pos = lseek(fd, size-1, SEEK_SET); 15 | write(fd, "", 1); 16 | close(fd); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /FileTransfer/client/createfile/file_ctl.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: file_ctl.h 3 | > Author: HeJie 4 | > Mail: sa614415@mail.ustc.edu.cn 5 | > Created Time: 2015年01月02日 星期五 17时04分28秒 6 | ************************************************************************/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | /* 14 | * @brief 创建指定大小的文件 15 | * @para filename 文件名;size 文件大小,单位字节 16 | * @return 0: 成功 其他: 失败 17 | */ 18 | int createfile(char *filename, int size); 19 | -------------------------------------------------------------------------------- /FileTransfer/client/createfile/file_ctl_test.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: file_ctl_test.c 3 | > Author: HeJie 4 | > Mail: sa614415@mail.ustc.edu.cn 5 | > Created Time: 2015年01月03日 星期六 16时39分48秒 6 | ************************************************************************/ 7 | 8 | #include "file_ctl.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main() 15 | { 16 | int i, fd, size=1024*1024*512; 17 | 18 | createfile("abc", size); 19 | if((fd = open("abc", O_RDWR)) == -1 ) 20 | { 21 | printf("open erro\n"); 22 | exit(-1); 23 | } 24 | struct stat filestat; 25 | fstat(fd ,&filestat); 26 | printf("file size = %ld\n",filestat.st_size); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /FileTransfer/client/tpool.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: tpool.c 3 | > Author: HeJie 4 | > Mail: sa614415@mail.ustc.edu.cn 5 | > Created Time: 2015年01月02日 星期五 17时04分28秒 6 | ************************************************************************/ 7 | 8 | #include "tpool.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | static tpool_t *tpool = NULL; 17 | 18 | /* 工作者线程函数, 从任务链表中取出任务并执行 */ 19 | static void* thread_routine(void *arg) 20 | { 21 | tpool_work_t *work; 22 | 23 | while(1) { 24 | /* 如果任务队列为空,且线程池未关闭,线程阻塞等待任务 */ 25 | pthread_mutex_lock(&tpool->queue_lock); 26 | while(!tpool->queue_head && !tpool->shutdown) { 27 | pthread_cond_wait(&tpool->queue_ready, &tpool->queue_lock); 28 | } 29 | 30 | /*查看线程池开关,如果线程池关闭,线程退出*/ 31 | if (tpool->shutdown) { 32 | pthread_mutex_unlock(&tpool->queue_lock); 33 | pthread_exit(NULL); 34 | } 35 | 36 | /*从任务链表中取出任务,执行任务*/ 37 | work = tpool->queue_head; 38 | tpool->queue_head = tpool->queue_head->next; 39 | pthread_mutex_unlock(&tpool->queue_lock); 40 | work->routine(work->arg); 41 | 42 | /*线程完成任务后,释放任务*/ 43 | free(work->arg); 44 | free(work); 45 | } 46 | return NULL; 47 | } 48 | 49 | /* 创建线程池 */ 50 | int tpool_create(int max_thr_num) 51 | { 52 | int i; 53 | 54 | /*创建进程池结构体*/ 55 | tpool = calloc(1, sizeof(tpool_t)); 56 | if (!tpool) { 57 | printf("%s: calloc tpool failed\n", __FUNCTION__); 58 | exit(1); 59 | } 60 | 61 | /* 初始化任务链表、互斥量、条件变量 */ 62 | tpool->max_thr_num = max_thr_num; 63 | tpool->shutdown = 0; 64 | tpool->queue_head = NULL; 65 | tpool->queue_tail = NULL; 66 | if (pthread_mutex_init(&tpool->queue_lock, NULL) !=0) { 67 | printf("%s: pthread_mutex_init failed, errno:%d, error:%s\n", 68 | __FUNCTION__, errno, strerror(errno)); 69 | exit(-1); 70 | } 71 | if (pthread_cond_init(&tpool->queue_ready, NULL) !=0 ) { 72 | printf("%s: pthread_cond_init failed, errno:%d, error:%s\n", 73 | __FUNCTION__, errno, strerror(errno)); 74 | exit(-1); 75 | } 76 | 77 | /* 创建worker线程 */ 78 | tpool->thr_id = calloc(max_thr_num, sizeof(pthread_t)); 79 | if (!tpool->thr_id) { 80 | printf("%s: calloc thr_id failed\n", __FUNCTION__); 81 | exit(1); 82 | } 83 | for (i = 0; i < max_thr_num; ++i) { 84 | if (pthread_create(&tpool->thr_id[i], NULL, thread_routine, NULL) != 0){ 85 | printf("%s:pthread_create failed, errno:%d, error:%s\n", __FUNCTION__, errno, strerror(errno)); 86 | exit(-1); 87 | } 88 | } 89 | return 0; 90 | } 91 | 92 | /* 销毁线程池 */ 93 | void tpool_destroy() 94 | { 95 | int i; 96 | tpool_work_t *member; 97 | 98 | if (tpool->shutdown) { 99 | return; 100 | } 101 | /*关闭线程池开关*/ 102 | tpool->shutdown = 1; 103 | 104 | /* 唤醒所有阻塞的线程 */ 105 | pthread_mutex_lock(&tpool->queue_lock); 106 | pthread_cond_broadcast(&tpool->queue_ready); 107 | pthread_mutex_unlock(&tpool->queue_lock); 108 | 109 | /*回收结束线程的剩余资源*/ 110 | for (i = 0; i < tpool->max_thr_num; ++i) { 111 | pthread_join(tpool->thr_id[i], NULL); 112 | } 113 | 114 | /*释放threadID数组*/ 115 | free(tpool->thr_id); 116 | 117 | /*释放未完成的任务*/ 118 | while(tpool->queue_head) { 119 | member = tpool->queue_head; 120 | tpool->queue_head = tpool->queue_head->next; 121 | free(member->arg); 122 | free(member); 123 | } 124 | 125 | /*销毁互斥量、条件变量*/ 126 | pthread_mutex_destroy(&tpool->queue_lock); 127 | pthread_cond_destroy(&tpool->queue_ready); 128 | 129 | /*释放进程池结构体*/ 130 | free(tpool); 131 | } 132 | 133 | /* 向线程池添加任务 */ 134 | int tpool_add_work(void*(*routine)(void*), void *arg) 135 | { 136 | /*work指向等待加入任务链表的任务*/ 137 | tpool_work_t *work; 138 | 139 | if (!routine){ 140 | printf("%s:Invalid argument\n", __FUNCTION__); 141 | return -1; 142 | } 143 | 144 | work = malloc(sizeof(tpool_work_t)); 145 | if (!work) { 146 | printf("%s:malloc failed\n", __FUNCTION__); 147 | return -1; 148 | } 149 | work->routine = routine; 150 | work->arg = arg; 151 | work->next = NULL; 152 | 153 | /*将任务结点添加到任务链表*/ 154 | pthread_mutex_lock(&tpool->queue_lock); 155 | /*任务链表为空*/ 156 | if ( !tpool->queue_head ) { 157 | // printf("first work in work-queue\n"); 158 | tpool->queue_head = work; 159 | tpool->queue_tail = work; 160 | } 161 | /*任务链表非空,查询任务链表末尾*/ 162 | else { 163 | // printf("not first work in work-queue\n"); 164 | tpool->queue_tail->next=work; 165 | tpool->queue_tail=work; 166 | } 167 | /* 通知工作者线程,有新任务添加 */ 168 | pthread_cond_signal(&tpool->queue_ready); 169 | pthread_mutex_unlock(&tpool->queue_lock); 170 | return 0; 171 | } 172 | -------------------------------------------------------------------------------- /FileTransfer/client/tpool.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: tpool.h 3 | > Author: HeJie 4 | > Mail: sa614415@mail.ustc.edu.cn 5 | > Created Time: 2015年01月02日 星期五 17时04分28秒 6 | ************************************************************************/ 7 | 8 | #ifndef THREAD_POOL_H__ 9 | #define THREAD_POOL_H__ 10 | 11 | #include 12 | 13 | /* 任务结点 */ 14 | typedef struct tpool_work { 15 | void* (*routine)(void*); /* 任务函数 */ 16 | void *arg; /* 传入任务函数的参数 */ 17 | struct tpool_work *next; 18 | }tpool_work_t; 19 | 20 | typedef struct tpool { 21 | int shutdown; /* 线程池是否销毁 */ 22 | int max_thr_num; /* 最大线程数 */ 23 | pthread_t *thr_id; /* 线程ID数组首地址 */ 24 | tpool_work_t *queue_head; /* 任务链表队首 */ 25 | tpool_work_t *queue_tail; /* 任务链表队尾 */ 26 | pthread_mutex_t queue_lock; 27 | pthread_cond_t queue_ready; 28 | }tpool_t; 29 | 30 | /* 31 | * @brief 创建线程池 32 | * @param max_thr_num 最大线程数 33 | * @return 0: 成功 其他: 失败 34 | */ 35 | int tpool_create(int max_thr_num); 36 | 37 | /* 38 | * @brief 销毁线程池 39 | */ 40 | void tpool_destroy(); 41 | 42 | /* 43 | * @brief 向线程池中添加任务 44 | * @param routine 任务函数指针 45 | * @param arg 任务函数参数 46 | * @return 0: 成功 其他:失败 47 | */ 48 | int tpool_add_work(void*(*routine)(void*), void *arg); 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /FileTransfer/client/work.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: work.c 3 | > Author: HeJie 4 | > Mail: sa614415@mail.ustc.edu.cn 5 | > Created Time: 2015年01月02日 星期五 17时04分28秒 6 | ************************************************************************/ 7 | 8 | #include "work.h" 9 | 10 | /*信息交换sockfd*/ 11 | int info_fd; 12 | 13 | extern char *mbegin; 14 | extern int port; 15 | 16 | /*结构体长度*/ 17 | int fileinfo_len = sizeof(struct fileinfo); 18 | socklen_t sockaddr_len = sizeof(struct sockaddr); 19 | int head_len = sizeof(struct head); 20 | 21 | int createfile(char *filename, int size) 22 | { 23 | int fd = open(filename, O_RDWR | O_CREAT); 24 | fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 25 | lseek(fd, size-1, SEEK_SET); 26 | write(fd, "", 1); 27 | close(fd); 28 | return 0; 29 | } 30 | 31 | 32 | struct head * new_fb_head(char *filename, int freeid, int *offset) 33 | { 34 | struct head * p_fhead = (struct head *)malloc(head_len); 35 | bzero(p_fhead, head_len); 36 | strcpy(p_fhead->filename, filename); 37 | p_fhead->id = freeid; 38 | p_fhead->offset = *offset; 39 | p_fhead->bs = BLOCKSIZE; 40 | *offset += BLOCKSIZE; 41 | return p_fhead; 42 | } 43 | 44 | 45 | void send_fileinfo(int sock_fd, char *fname, struct stat* p_fstat, struct fileinfo *p_finfo, int *p_last_bs) 46 | { 47 | /*初始化fileinfo*/ 48 | bzero(p_finfo, fileinfo_len); 49 | strcpy(p_finfo->filename, fname); 50 | p_finfo->filesize = p_fstat->st_size; 51 | 52 | /*最后一个分块可能不足一个标准分块*/ 53 | int count = p_fstat->st_size/BLOCKSIZE; 54 | if(p_fstat->st_size%BLOCKSIZE == 0){ 55 | p_finfo->count = count; 56 | } 57 | else{ 58 | p_finfo->count = count+1; 59 | *p_last_bs = p_fstat->st_size - BLOCKSIZE*count; 60 | } 61 | p_finfo->bs = BLOCKSIZE; 62 | 63 | /*发送type和文件信息*/ 64 | char send_buf[100]= {0}; 65 | int type=0; 66 | memcpy(send_buf, &type, INT_SIZE); 67 | memcpy(send_buf+INT_SIZE, p_finfo, fileinfo_len); 68 | send(sock_fd, send_buf, fileinfo_len+INT_SIZE, 0); 69 | 70 | printf("-------- fileinfo -------\n"); 71 | printf("filename= %s\nfilesize= %d\ncount= %d\nblocksize= %d\n", p_finfo->filename, p_finfo->filesize, p_finfo->count, p_finfo->bs); 72 | printf("-------------------------\n"); 73 | return; 74 | } 75 | 76 | void * send_filedata(void *args) 77 | { 78 | struct head * p_fhead = (struct head *)args; 79 | printf("------- blockhead -------\n"); 80 | printf("filename= %s\nThe filedata id= %d\noffset= %d\nbs= %d\n", p_fhead->filename, p_fhead->id, p_fhead->offset, p_fhead->bs); 81 | printf("-------------------------\n"); 82 | 83 | int sock_fd = Client_init(SERVER_IP); 84 | //set_fd_noblock(sock_fd); 85 | 86 | /*发送type和数据块头部*/ 87 | char send_buf[100]= {0}; 88 | int type=255; 89 | memcpy(send_buf, &type, INT_SIZE); 90 | memcpy(send_buf+INT_SIZE, p_fhead, head_len); 91 | int sendsize=0, len = head_len+INT_SIZE; 92 | char *p=send_buf; 93 | while(1){ 94 | if((send(sock_fd, p, 1, 0) >0)){ 95 | ++sendsize; 96 | if(sendsize == len) 97 | break; 98 | ++p; 99 | } 100 | } 101 | // printf("head_len = %d ; send head: sendsize = %d\n",head_len, sendsize); 102 | 103 | /*发送数据块*/ 104 | printf("Thread : send filedata\n"); 105 | int i=0, send_size=0, num=p_fhead->bs/SEND_SIZE; 106 | char *fp=mbegin+p_fhead->offset; 107 | for(i=0; i File Name: work.h 4 | > Author: HeJie 5 | > Mail: sa614415@mail.ustc.edu.cn 6 | > Created Time: 2015年01月02日 星期五 17时04分28秒 7 | ************************************************************************/ 8 | 9 | #ifndef WORK_H__ 10 | #define WORK_H__ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | 33 | #define SERVER_IP "127.0.0.1" //server IP 34 | #define PORT 10000 //Server端口 35 | #define THREAD_NUM 4 //线程池大小 36 | #define FILENAME_MAXLEN 30 //文件名最大长度 37 | #define INT_SIZE 4 //int类型长度 38 | 39 | //#define SEND_SIZE 32768 //32K 40 | #define SEND_SIZE 65536 //64K 41 | //#define SEND_SIZE 131072 //128K 42 | //#define SEND_SIZE 262144 //256K 43 | 44 | //#define BLOCKSIZE 134217728 //128M 45 | //#define BLOCKSIZE 268435456 //256M 46 | #define BLOCKSIZE 536870912 //512M 47 | //#define BLOCKSIZE 1073741824 //1G 48 | 49 | /*文件信息*/ 50 | struct fileinfo{ 51 | char filename[FILENAME_MAXLEN]; //文件名 52 | int filesize; //文件大小 53 | int count; //分块数量 54 | int bs; //标准分块大小 55 | }; 56 | 57 | /*分块头部信息*/ 58 | struct head{ 59 | char filename[FILENAME_MAXLEN]; //文件名 60 | int id; //分块所属文件的id,gconn[CONN_MAX]数组的下标 61 | int offset; //分块在原文件中偏移 62 | int bs; //本文件块实际大小 63 | }; 64 | 65 | /*创建大小为size的文件*/ 66 | int createfile(char *filename, int size); 67 | 68 | /*设置fd非阻塞*/ 69 | void set_fd_noblock(int fd); 70 | 71 | /*初始化Client*/ 72 | int Client_init(char *ip); 73 | 74 | /*发送文件信息,初始化分块头部信息*/ 75 | /*last_bs==0:所有分块都是标准分块;flag>0:最后一个分块不是标准分块,last_bs即为最后一块大小*/ 76 | void send_fileinfo(int sock_fd //要发送文件fd 77 | , char *fname //filename 78 | , struct stat* p_fstat //文件属性结构体 79 | , struct fileinfo *p_finfo //返回初始化后的文件信息 80 | , int *flag); //最后一个分块是否时标准分块,0代表是;1代表不是 81 | 82 | /*发送文件数据块*/ 83 | void * send_filedata(void *args); 84 | 85 | /*生成文件块头部*/ 86 | struct head * new_fb_head(char *filename, int freeid, int *offset); 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /FileTransfer/server/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for Server 3 | # 4 | all: 5 | gcc -o server tpool.c work.c server.c -lpthread 6 | 7 | clean: 8 | rm server 9 | -------------------------------------------------------------------------------- /FileTransfer/server/args: -------------------------------------------------------------------------------- 1 | net.ipv4.tcp_rmem=4096 4194304 4194304 2 | net.ipv4.tcp_wmem=98304 4194304 4194304 3 | net.ipv4.tcp_mem=98304 4194304 4194304 4 | net.core.rmem_default=262144 5 | net.core.wmem_default=262144 6 | net.core.rmem_max=4194304 7 | net.core.wmem_max=4194304 8 | -------------------------------------------------------------------------------- /FileTransfer/server/server.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: server.c 3 | > Author: HeJie 4 | > Mail: sa614415@mail.ustc.edu.cn 5 | > Created Time: 2015年01月03日 星期五 01时01分39秒 6 | ************************************************************************/ 7 | #include "work.h" 8 | #include "tpool.h" 9 | 10 | int main(int argc, char **argv) 11 | { 12 | printf("##################### Server #####################\n"); 13 | int port = PORT; 14 | if (argc>1) 15 | port = atoi(argv[1]); 16 | 17 | /*创建线程池*/ 18 | if (tpool_create(THREAD_NUM) != 0) { 19 | printf("tpool_create failed\n"); 20 | exit(-1); 21 | } 22 | printf("--- Thread Pool Strat ---\n"); 23 | 24 | /*初始化server,监听请求*/ 25 | int listenfd = Server_init(port); 26 | socklen_t sockaddr_len = sizeof(struct sockaddr); 27 | 28 | /*epoll*/ 29 | static struct epoll_event ev, events[EPOLL_SIZE]; 30 | int epfd = epoll_create(EPOLL_SIZE); 31 | ev.events = EPOLLIN; 32 | ev.data.fd = listenfd; 33 | epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev); 34 | 35 | while(1){ 36 | int events_count = epoll_wait(epfd, events, EPOLL_SIZE, -1); 37 | int i=0; 38 | 39 | /*接受连接,添加work到work-Queue*/ 40 | for(; i 0 ) 46 | { 47 | printf("EPOLL: Received New Connection Request---connfd= %d\n",connfd); 48 | struct args *p_args = (struct args *)malloc(sizeof(struct args)); 49 | p_args->fd = connfd; 50 | p_args->recv_finfo = recv_fileinfo; 51 | p_args->recv_fdata = recv_filedata; 52 | 53 | /*添加work到work-Queue*/ 54 | tpool_add_work(worker, (void*)p_args); 55 | } 56 | } 57 | } 58 | } 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /FileTransfer/server/shell: -------------------------------------------------------------------------------- 1 | sudo chmod 777 /etc/sysctl.conf 2 | sudo cat args >>/etc/sysctl.conf 3 | sudo chmod 644 /etc/sysctl.conf 4 | sudo sysctl -p 5 | -------------------------------------------------------------------------------- /FileTransfer/server/tpool.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: tpool.c 3 | > Author: HeJie 4 | > Mail: sa614415@mail.ustc.edu.cn 5 | > Created Time: 2015年01月02日 星期五 17时04分28秒 6 | ************************************************************************/ 7 | 8 | #include "tpool.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | static tpool_t *tpool = NULL; 17 | 18 | /* 工作者线程函数, 从任务链表中取出任务并执行 */ 19 | static void* thread_routine(void *arg) 20 | { 21 | tpool_work_t *work; 22 | 23 | while(1) { 24 | /* 如果任务队列为空,且线程池未关闭,线程阻塞等待任务 */ 25 | pthread_mutex_lock(&tpool->queue_lock); 26 | while(!tpool->queue_head && !tpool->shutdown) { 27 | pthread_cond_wait(&tpool->queue_ready, &tpool->queue_lock); 28 | } 29 | 30 | /*查看线程池开关,如果线程池关闭,线程退出*/ 31 | if (tpool->shutdown) { 32 | pthread_mutex_unlock(&tpool->queue_lock); 33 | pthread_exit(NULL); 34 | } 35 | 36 | /*从任务链表中取出任务,执行任务*/ 37 | work = tpool->queue_head; 38 | tpool->queue_head = tpool->queue_head->next; 39 | pthread_mutex_unlock(&tpool->queue_lock); 40 | work->routine(work->arg); 41 | 42 | /*线程完成任务后,释放任务*/ 43 | free(work->arg); 44 | free(work); 45 | } 46 | return NULL; 47 | } 48 | 49 | /* 创建线程池 */ 50 | int tpool_create(int max_thr_num) 51 | { 52 | int i; 53 | 54 | /*创建进程池结构体*/ 55 | tpool = calloc(1, sizeof(tpool_t)); 56 | if (!tpool) { 57 | printf("%s: calloc tpool failed\n", __FUNCTION__); 58 | exit(1); 59 | } 60 | 61 | /* 初始化任务链表、互斥量、条件变量 */ 62 | tpool->max_thr_num = max_thr_num; 63 | tpool->shutdown = 0; 64 | tpool->queue_head = NULL; 65 | tpool->queue_tail = NULL; 66 | if (pthread_mutex_init(&tpool->queue_lock, NULL) !=0) { 67 | printf("%s: pthread_mutex_init failed, errno:%d, error:%s\n", 68 | __FUNCTION__, errno, strerror(errno)); 69 | exit(-1); 70 | } 71 | if (pthread_cond_init(&tpool->queue_ready, NULL) !=0 ) { 72 | printf("%s: pthread_cond_init failed, errno:%d, error:%s\n", 73 | __FUNCTION__, errno, strerror(errno)); 74 | exit(-1); 75 | } 76 | 77 | /* 创建worker线程 */ 78 | tpool->thr_id = calloc(max_thr_num, sizeof(pthread_t)); 79 | if (!tpool->thr_id) { 80 | printf("%s: calloc thr_id failed\n", __FUNCTION__); 81 | exit(1); 82 | } 83 | for (i = 0; i < max_thr_num; ++i) { 84 | if (pthread_create(&tpool->thr_id[i], NULL, thread_routine, NULL) != 0){ 85 | printf("%s:pthread_create failed, errno:%d, error:%s\n", __FUNCTION__, errno, strerror(errno)); 86 | exit(-1); 87 | } 88 | } 89 | return 0; 90 | } 91 | 92 | /* 销毁线程池 */ 93 | void tpool_destroy() 94 | { 95 | int i; 96 | tpool_work_t *member; 97 | 98 | if (tpool->shutdown) { 99 | return; 100 | } 101 | /*关闭线程池开关*/ 102 | tpool->shutdown = 1; 103 | 104 | /* 唤醒所有阻塞的线程 */ 105 | pthread_mutex_lock(&tpool->queue_lock); 106 | pthread_cond_broadcast(&tpool->queue_ready); 107 | pthread_mutex_unlock(&tpool->queue_lock); 108 | 109 | /*回收结束线程的剩余资源*/ 110 | for (i = 0; i < tpool->max_thr_num; ++i) { 111 | pthread_join(tpool->thr_id[i], NULL); 112 | } 113 | 114 | /*释放threadID数组*/ 115 | free(tpool->thr_id); 116 | 117 | /*释放未完成的任务*/ 118 | while(tpool->queue_head) { 119 | member = tpool->queue_head; 120 | tpool->queue_head = tpool->queue_head->next; 121 | free(member->arg); 122 | free(member); 123 | } 124 | 125 | /*销毁互斥量、条件变量*/ 126 | pthread_mutex_destroy(&tpool->queue_lock); 127 | pthread_cond_destroy(&tpool->queue_ready); 128 | 129 | /*释放进程池结构体*/ 130 | free(tpool); 131 | } 132 | 133 | /* 向线程池添加任务 */ 134 | int tpool_add_work(void*(*routine)(void*), void *arg) 135 | { 136 | /*work指向等待加入任务链表的任务*/ 137 | tpool_work_t *work; 138 | 139 | if (!routine){ 140 | printf("%s:Invalid argument\n", __FUNCTION__); 141 | return -1; 142 | } 143 | 144 | work = malloc(sizeof(tpool_work_t)); 145 | if (!work) { 146 | printf("%s:malloc failed\n", __FUNCTION__); 147 | return -1; 148 | } 149 | work->routine = routine; 150 | work->arg = arg; 151 | work->next = NULL; 152 | 153 | /*将任务结点添加到任务链表*/ 154 | pthread_mutex_lock(&tpool->queue_lock); 155 | /*任务链表为空*/ 156 | if ( !tpool->queue_head ) { 157 | // printf("first work in work-queue\n"); 158 | tpool->queue_head = work; 159 | tpool->queue_tail = work; 160 | } 161 | /*任务链表非空,查询任务链表末尾*/ 162 | else { 163 | // printf("not first work in work-queue\n"); 164 | tpool->queue_tail->next=work; 165 | tpool->queue_tail=work; 166 | } 167 | /* 通知工作者线程,有新任务添加 */ 168 | pthread_cond_signal(&tpool->queue_ready); 169 | pthread_mutex_unlock(&tpool->queue_lock); 170 | return 0; 171 | } 172 | -------------------------------------------------------------------------------- /FileTransfer/server/tpool.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: tpool.h 3 | > Author: HeJie 4 | > Mail: sa614415@mail.ustc.edu.cn 5 | > Created Time: 2015年01月02日 星期五 17时04分28秒 6 | ************************************************************************/ 7 | 8 | #ifndef THREAD_POOL_H__ 9 | #define THREAD_POOL_H__ 10 | 11 | #include 12 | 13 | /* 任务结点 */ 14 | typedef struct tpool_work { 15 | void* (*routine)(void*); /* 任务函数 */ 16 | void *arg; /* 传入任务函数的参数 */ 17 | struct tpool_work *next; 18 | }tpool_work_t; 19 | 20 | /* 线程池 */ 21 | typedef struct tpool { 22 | int shutdown; /* 线程池是否销毁 */ 23 | int max_thr_num; /* 最大线程数 */ 24 | pthread_t *thr_id; /* 线程ID数组首地址 */ 25 | tpool_work_t *queue_head; /* 任务链表队首 */ 26 | tpool_work_t *queue_tail; /* 任务链表队尾 */ 27 | pthread_mutex_t queue_lock; 28 | pthread_cond_t queue_ready; 29 | }tpool_t; 30 | 31 | /* 创建线程池 */ 32 | int tpool_create(int max_thr_num); 33 | 34 | /* 销毁线程池 */ 35 | void tpool_destroy(); 36 | 37 | /* 向线程池中添加任务 */ 38 | int tpool_add_work(void*(*routine)(void*), void *arg); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /FileTransfer/server/work.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: work.c 3 | > Author: HeJie 4 | > Mail: sa614415@mail.ustc.edu.cn 5 | > Created Time: 2015年01月02日 星期五 17时04分28秒 6 | ************************************************************************/ 7 | 8 | #include "work.h" 9 | 10 | /*gconn[]数组存放连接信息,带互斥锁*/ 11 | int freeid = 0; 12 | struct conn gconn[CONN_MAX]; 13 | pthread_mutex_t conn_lock = PTHREAD_MUTEX_INITIALIZER; 14 | 15 | /*结构体长度*/ 16 | int fileinfo_len = sizeof(struct fileinfo); 17 | socklen_t sockaddr_len = sizeof(struct sockaddr); 18 | int head_len = sizeof(struct head); 19 | int conn_len = sizeof(struct conn); 20 | 21 | int createfile(char *filename, int size) 22 | { 23 | int fd = open(filename, O_RDWR | O_CREAT); 24 | fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 25 | lseek(fd, size-1, SEEK_SET); 26 | write(fd, "", 1); 27 | close(fd); 28 | return 0; 29 | } 30 | 31 | /*工作线程,分析type,选择工种*/ 32 | void * worker(void *argc) 33 | { 34 | struct args *pw = (struct args *)argc; 35 | int conn_fd = pw->fd; 36 | 37 | char type_buf[INT_SIZE] = {0}; 38 | char *p=type_buf; 39 | int recv_size=0; 40 | while(1){ 41 | if( recv(conn_fd, p, 1, 0) == 1 ){ 42 | ++recv_size; 43 | if(recv_size == INT_SIZE) 44 | break; 45 | ++p; 46 | } 47 | } 48 | 49 | int type=*((int*)type_buf); 50 | switch (type){ 51 | /*接收文件信息*/ 52 | case 0: 53 | printf("## worker ##\nCase %d: the work is recv file-info\n", type); 54 | pw->recv_finfo(conn_fd); 55 | break; 56 | /*接收文件块*/ 57 | case 255: 58 | printf("## worker ##\nCase %d: the work is recv file-data\n", type); 59 | pw->recv_fdata(conn_fd); 60 | break; 61 | default: 62 | printf("unknown type!"); 63 | return NULL; 64 | } 65 | 66 | return NULL; 67 | } 68 | 69 | /*接收文件信息,添加连接到gobalconn[]数组,创建填充文件,map到内存*/ 70 | void recv_fileinfo(int sockfd) 71 | { 72 | /*接收文件信息*/ 73 | char fileinfo_buf[100] = {0}; 74 | bzero(fileinfo_buf, fileinfo_len); 75 | int n=0; 76 | for(n=0; n 0){ 168 | if((size = recv(sockfd, fp, RECVBUF_SIZE, 0)) >0){ 169 | fp+=size; 170 | remain_size-=size; 171 | // printf("recv size = %d ",size); 172 | // printf("remain size = %d\n",remain_size); 173 | } 174 | } 175 | 176 | printf("----------------- Recv a fileblock ----------------- \n"); 177 | 178 | /*增加recv_count,判断是否是最后一个分块,如果是最后一个分块,同步map与文件,释放gconn*/ 179 | pthread_mutex_lock(&conn_lock); 180 | gconn[recv_id].recvcount++; 181 | if(gconn[recv_id].recvcount == gconn[recv_id].count){ 182 | munmap((void *)gconn[recv_id].mbegin, gconn[recv_id].filesize); 183 | 184 | printf("----------------- Recv a File ----------------- \n "); 185 | 186 | int fd = gconn[recv_id].info_fd; 187 | close(fd); 188 | bzero(&gconn[recv_id], conn_len); 189 | } 190 | pthread_mutex_unlock(&conn_lock); 191 | 192 | close(sockfd); 193 | return; 194 | } 195 | 196 | /*初始化Server,监听Client*/ 197 | int Server_init(int port) 198 | { 199 | int listen_fd; 200 | struct sockaddr_in server_addr; 201 | if((listen_fd = socket(AF_INET, SOCK_STREAM, 0))== -1) 202 | { 203 | fprintf(stderr, "Creating server socket failed."); 204 | exit(-1); 205 | } 206 | set_fd_noblock(listen_fd); 207 | 208 | bzero(&server_addr, sockaddr_len); 209 | server_addr.sin_family = AF_INET; 210 | server_addr.sin_port = htons(port); 211 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 212 | 213 | if(bind(listen_fd, (struct sockaddr *) &server_addr, sockaddr_len) == -1) 214 | { 215 | fprintf(stderr, "Server bind failed."); 216 | exit(-1); 217 | } 218 | 219 | if(listen(listen_fd, LISTEN_QUEUE_LEN) == -1) 220 | { 221 | fprintf(stderr, "Server listen failed."); 222 | exit(-1); 223 | } 224 | return listen_fd; 225 | } 226 | 227 | void set_fd_noblock(int fd) 228 | { 229 | int flag=fcntl(fd, F_GETFL, 0); 230 | fcntl(fd, F_SETFL, flag | O_NONBLOCK); 231 | return; 232 | } 233 | -------------------------------------------------------------------------------- /FileTransfer/server/work.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: work.h 3 | > Author: HeJie 4 | > Mail: sa614415@mail.ustc.edu.cn 5 | > Created Time: 2015年01月02日 星期五 17时04分28秒 6 | ************************************************************************/ 7 | 8 | #ifndef SERVER_H__ 9 | #define SERVER_H__ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #define PORT 10000 //监听端口 28 | #define LISTEN_QUEUE_LEN 100 //listen队列长度 29 | #define THREAD_NUM 8 //线程池大小 30 | #define CONN_MAX 10 //支持最大连接数,一个连接包含多个socket连接(多线程) 31 | #define EPOLL_SIZE 50 //epoll最大监听fd数量 32 | #define FILENAME_MAXLEN 30 //文件名最大长度 33 | #define INT_SIZE 4 //int类型长度 34 | 35 | /*一次rece接收数据大小*/ 36 | //#define RECVBUF_SIZE 4096 //4K 37 | //#define RECVBUF_SIZE 32768 //32K 38 | //#define RECVBUF_SIZE 131072 //128K 39 | //#define RECVBUF_SIZE 262144 //256K 40 | #define RECVBUF_SIZE 65536 //64K 41 | 42 | /*文件信息*/ 43 | struct fileinfo{ 44 | char filename[FILENAME_MAXLEN]; //文件名 45 | int filesize; //文件大小 46 | int count; //分块数量 47 | int bs; //标准分块大小 48 | }; 49 | 50 | /*分块头部信息*/ 51 | struct head{ 52 | char filename[FILENAME_MAXLEN]; //文件名 53 | int id; //分块所属文件的id,gconn[CONN_MAX]数组的下标 54 | int offset; //分块在原文件中偏移 55 | int bs; //本文件块实际大小 56 | }; 57 | 58 | //与客户端关联的连接,每次传输建立一个,在多线程之间共享 59 | struct conn{ 60 | int info_fd; //信息交换socket:接收文件信息、文件传送通知client 61 | char filename[FILENAME_MAXLEN]; //文件名 62 | int filesize; //文件大小 63 | int bs; //分块大小 64 | int count; //分块数量 65 | int recvcount; //已接收块数量,recv_count == count表示传输完毕 66 | char *mbegin; //mmap起始地址 67 | int used; //使用标记,1代表使用,0代表可用 68 | }; 69 | 70 | /*线程参数*/ 71 | struct args{ 72 | int fd; 73 | void (*recv_finfo)(int fd); 74 | void (*recv_fdata)(int fd); 75 | }; 76 | 77 | /*创建大小为size的文件*/ 78 | int createfile(char *filename, int size); 79 | 80 | /*初始化Server:监听请求,返回listenfd*/ 81 | int Server_init(int port); 82 | 83 | /*设置fd非阻塞*/ 84 | void set_fd_noblock(int fd); 85 | 86 | /*接收文件信息,向Client返回本次文件传输使用的freeid*/ 87 | void recv_fileinfo(int sockfd); 88 | 89 | /*接收文件块*/ 90 | void recv_filedata(int sockfd); 91 | 92 | /*线程函数*/ 93 | void * worker(void *argc); 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /FileTransfer/server架构.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerryos/FileTransfer/168e236826b586d99058a2727dae0c4d4d58b989/FileTransfer/server架构.jpeg -------------------------------------------------------------------------------- /FileTransfer/演示.ppt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerryos/FileTransfer/168e236826b586d99058a2727dae0c4d4d58b989/FileTransfer/演示.ppt --------------------------------------------------------------------------------