安全文件传输系统组成: 客户端:用户登录,上传文件,下载文件,浏览文件列表 服务器:用户登录,服务器配置,多线程管理,上传下载管理,系统日志 协议:自定义传输协议 要求: 1.系统要求必须支持将每个文件数据进行存储 2.客户端支持从服务器中获取文件的元数据 3.服务端要求是必须多线程的,能够允许多个客户同时连接 4.服务端必须记录文件操作事件日志,能够支持用户名和密码验证 5.客户端具有上传和下载能力,并且要求先检查磁盘空间 详细深入了解见SDK-SFSS/doc openssl编程.pdf openssl中文简介.doc openssl编程示范.doc mkdir openssl thread sfss cp /home/OpenSSL/代码/编程规范 ./openssl 1.生成RSA密钥: cd openssl openssl genrsa -out privkey.pem 2048 该命令生成一个2048位的privkey.pem,该密钥为私钥。 2.生成数字证书: openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095 生成数字证书cacert.pem,是数字化的文件,里面有一个实体(网站,个人等)的公共密钥和其它属性如名称等。 3.编译服务器,客户端程序 gcc server.c -o server -lssl gcc client.c -o client -lssl 4.程序运行 ./server //开始监听,等待客户端连接 ./client 192.168.1.25 7838 >please input the filename of you want to load: 说明:192.168.1.24是客户端IP地址,端口号是7838,客户端从服务端获得证书信息,客户端等待输入上传文件名, >/root/t.c 此时客户端把t.c文件上传到服务端的/newfile目录下。 5.线程池范例设计: 因为是模拟手机程序开发,服务器运行时能同时接收到多个客户端的连接。服务端需要不停的创建和销毁线程,这将耗费大量的系统资源。因此服务端运用了线程池来管理线程,这将大大降低系统资源。 应用程序池管理线程,节约系统资源,重复利用已经创建的线程,在线程池管理的基本源程序中需要用到条件变量来实现线程的阻塞和唤醒管理。 详细参考: 线程池介绍.doc 条件变量.doc /SDK-SFSS/线程池/编程规范thread.c给出了线程池的基本实现,它用3个线程完成的10个任务,代码解析见源代码。 gcc thread.c -o thread -lpthread ./thread 3个线程被10个任务重复利用,这样节约了创建和销毁线程所工会费的时间和资源,当需要重复创建和销毁线程时线程池的管理尤为重要, 6.服务端,客户端程序设计: 详细设计见/SDK-SFSS/doc/详细设计.pdf 服务端编译: openssl genrsa -out privkey.pem 2048 openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095 gcc server.c -o server -lssl -lpthread 其中server为可执行程序,privkey.pem为私钥,cacert.pem为数字证书。 客户端编译: gcc client.c -o client -lssl -lpthread 7.测试 ./server 添加client的user/111 ./client 192.168.1.24 输入ID/PASSWORD 出现1.update files 2.download files选项 8.代码分析: 本项目分服务端和客户端server.h, server.c, client.c server.h #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/stat.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <unistd.h> #include <fcntl.h> #include <arpa/inet.h> #include <pthread.h> #include <semaphore.h> #include <sys/ipc.h> #include <sys/vfs.h> #include <dirent.h> #include <netinet/in.h> #include <sys/file.h> #include <netdb.h> #include <signal.h> #include <openssl/ssl.h> #include <openssl/err.h> struct FilePackage { char cmd; int filesize; int ack; char username[50]; char filename[125]; char buf[1024]; }; /*打包函数*/ struct FilePackage pack(char tCmd, char* tBuf, char* tFilename, int tFilesize, int tAck,int count,char *uname) { struct FilePackage tPackage; tPackage.cmd = tCmd; // strcpy(tPackage.buf, tBuf); // strncpy(tPackage.buf, tBuf,1024); memcpy(tPackage.buf,tBuf,count); strcpy(tPackage.filename, tFilename); strcpy(tPackage.username, uname); tPackage.filesize = tFilesize; tPackage.ack = tAck; return tPackage; } server.c #include "server.h" //#define DEFDIR "./" #define THREADNUM 20 /*--------------全局变量---------------------*/ static int MaxClientNum=0; /*客服端最大连接数*/ static int CurrentClientNum=0; /*当前客服端连接数*/ static int IsRun=0; /*判断服务器是否开启*/ static int IsExit=0; /*判断是否退出服务器*/ static int ThreadIdleId[THREADNUM]={0}; /*线程池中空闲线程的线程号*/ static int ThreadBusyId[THREADNUM]={0}; /*线程池中工作线程的线程号*/ static int TaskId[THREADNUM]={0}; static int TIdleNum=0; /*ThreadIdleId数组的序列号*/ static int TBusyNum=0; /*ThreadBusyId数组的序列号*/ static int TaskNum=0; pthread_t id; /*线程号*/ pthread_mutex_t pthreadMutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t pthreadCond = PTHREAD_COND_INITIALIZER; char Admin[1024]; /*记录管理员帐号与密码*/ char User[1024]; /*记录用户帐号与密码*/ char clientIP[15]; char filelist[1024]; /*文件列表*/ SSL_CTX *ctx; int sockfd; int new_fd; int tempsockfd; struct sockaddr_in server_addr; struct sockaddr_in client_addr; int sin_size,portnumber = 3333; char userdir[50]="\0"; struct FilePackage buff; /*接受客服端数据包*/ /*--------------处理函数---------------------*/ void InitAU(); /*将文件中管理员/用户的帐号信息读入数组*/ int InitMaxClientNum(); /*初始化客服端最大连接数*/ void mainMenu(); /*主菜单处理函数*/ void mainThread(); /*主线程处理函数*/ void process(); /*用户处理函数*/ struct FilePackage unpack(SSL * ,struct FilePackage ); /*解包函数*/ int CheckClient(char* , char* ); /*检测用户名与密码是否正确*/ void getlist(char *); /*获取文件列表函数*/ void receivePipBroken(int ); /*捕获pipe断开异常*/ char* getCurrentTime(); /*获取当前时间*/ void CreateThreadPool(); /*创建线程池*/ void MoveToIdle(int ); /*线程执行结束后,把自己放入到空闲线程中*/ void MoveToBusy(int ); /*移入到忙碌线程中去*/ void AddTask(int ); /*把任务添加到线程池中*/ /*--------------主函数---------------------*/ int main(int argc, char *argv[]) { pthread_t controlId; pthread_t mainId; MaxClientNum=InitMaxClientNum(); /*初始化客服端最大连接数*/ InitAU(); printf("\033[36m***********\033[0m\033[34mWelcome to Secure File Storage System\033[0m\033[36m**************\n\033[0m"); printf("\033[36m*\033[0m \033[31m ****** ****** ****** ****** \033[0m \033[36m *\n\033[0m\033[0m"); printf("\033[36m*\033[0m \033[31m ** * ** ** \033[0m \033[36m *\n\033[0m\033[0m"); printf("\033[36m*\033[0m \033[31m ***** ****** ***** ***** \033[0m \033[36m *\n\033[0m\033[0m"); printf("\033[36m*\033[0m \033[31m ** * ** ** \033[0m \033[36m *\n\033[0m\033[0m"); printf("\033[36m*\033[0m \033[31m ****** * ****** ****** \033[0m \033[34mKJC\033[0m \033[36m*\n\033[0m\033[0m"); printf("\033[36m**************************************************************\n\033[0m"); int flag=1,nflag=1; /*flag为1表示登陆错误,为0表示登陆成功*/ char AdminName[20]="\0"; char AdminPwd[20]="\0"; char AN[20]="\0"; char AP[20]="\0"; char *pAdmin=Admin; int i=0; while(flag!=0) /*管理员登陆*/ { printf("Admin Id:"); scanf("%s",AdminName); printf("Admin PassWord:"); scanf("%s",AdminPwd); while(nflag!=0) /*检查用户名是否存在*/ { while(*pAdmin!='*'&&(*pAdmin)!='\0') { if(i<20) { AN[i]=*(pAdmin); ++i; ++pAdmin; } } ++pAdmin; /*跳过*号*/ i=0; while(*pAdmin!='#'&&(*pAdmin)!='\0') { if(i<20) { AP[i]=*(pAdmin); ++i; ++pAdmin; } } ++pAdmin; /*跳过#号*/ if(strcmp(AN,AdminName)==0) { nflag=0; if(strcmp(AP,AdminPwd)==0) { flag=0; printf("\n\033[33mlogin success!\033[0m\n\n"); break; } else { nflag=1; memset(AP,'\0',20); memset(AN,'\0',20); pAdmin=Admin; printf("\n\033[33mAdmin name or passwd is error!\033[0m\n\n"); i=0; break; } } else if(*pAdmin=='\0') { pAdmin=Admin; i=0; memset(AP,'\0',20); memset(AN,'\0',20); printf("\n\033[33mAdmin name or passwd is error!\033[0m\n\n"); break; } i=0; memset(AP,'\0',20); memset(AN,'\0',20); } }//while结束 if((pthread_create(&controlId,NULL,(void *)mainMenu,NULL)) != 0) { printf("\033[33mCreate menu error!\033[0m\n"); } if((pthread_create(&mainId,NULL,(void *)mainThread,NULL)) != 0) { printf("\033[33mCreate menu error!\033[0m\n"); } pthread_join(controlId,NULL); pthread_join(mainId,NULL); return 0; } /*菜单函数*/ void mainMenu() { int choice; int cConfig; int flag=1; int fdMax; int fdAdmin; int fdUser; char NewAd[20]="\0"; /*存放新增用户帐号和密码*/ char NewAdPwd[20]="\0"; char Wadmin[45]="\0"; if((fdMax = open("./maxclientnum.txt",O_RDWR)) == -1) { printf("\033[31mmaxclientnum.txt open error!\033[0m\n"); exit(-1); } if((fdAdmin = open("./admin.txt",O_WRONLY|O_APPEND)) == -1) { printf("\033[31madmin.txt file open error!\033[0m\n"); exit(-1); } if((fdUser = open("./user.txt",O_WRONLY|O_APPEND)) == -1) { printf("\033[31muser.txt file open error!\033[0m\n"); exit(-1); } while(1) { printf(" \033[34m***********Server console***********\033[0m\n"); printf(" \033[34m*\033[0m 1.Configure \033[34m*\033[0m\n"); printf(" \033[34m*\033[0m 2.Run server \033[34m*\033[0m\n"); printf(" \033[34m*\033[0m 3.Stop server \033[34m*\033[0m\n"); printf(" \033[34m*\033[0m 4.Show status \033[34m*\033[0m\n"); printf(" \033[34m*\033[0m 5.Exit \033[34m*\033[0m\n"); printf(" \033[34m************************************\033[0m\n"); printf(" Please input the server command number:"); scanf("%d",&choice); system("clear"); switch(choice) { case 1: /*服务器配置*/ { flag=1; while(flag!=0) { printf(" \033[34m***************Configure**************\033[0m\n"); printf(" \033[34m*\033[0m 1.Set maximum client \033[34m*\033[0m\n"); printf(" \033[34m*\033[0m 2.Add admin account \033[34m*\033[0m\n"); printf(" \033[34m*\033[0m 3.Add client account \033[34m*\033[0m\n"); printf(" \033[34m*\033[0m 4.Go back \033[34m*\033[0m\n"); printf(" \033[34m**************************************\033[0m\n"); printf(" Please input the configuration command number:"); scanf("%d",&cConfig); system("clear"); switch(cConfig) { case 1: /*设置最大客服端连接数*/ { int changeMax; while(flag!=0) { printf("\033[33mthe current max client num is:\033[31m%d\n",MaxClientNum); printf("\033[34minput the max num U want change:"); scanf("%d",&changeMax); if(changeMax<0) { printf("\033[34mU input the num is below 0\n"); } else { char wr[3]; flag=0; MaxClientNum=changeMax; sprintf(wr,"%d",MaxClientNum); /*将一个整数转为字符*/ if(write(fdMax,wr,strlen(wr))<0) { printf("write to file error!\n"); exit(-1); } printf("\033[34mthe new max client num is:\033[31m%d\n",MaxClientNum); } } } break; case 2: /*新增管理员用户*/ { // char userdir[50]="\0"; printf("\033[34minput the new admin name:"); scanf("%s",NewAd); printf("\033[34minput the new admin passwd:"); scanf("%s",NewAdPwd); strcat(Wadmin,NewAd); strcat(Wadmin,"*"); strcat(Wadmin,NewAdPwd); strcat(Wadmin,"#"); // strcat(userdir,"./"); // strcat(userdir,NewAd); // printf("%s\n",userdir); if(write(fdAdmin,Wadmin,strlen(Wadmin)) < 0) { perror(" \033[31mwrite admin.txt error\033[0m\n"); exit(1); } else { printf("\033[31madd admin success!\n"); } } break; case 3: /*新增用户帐户*/ { char tuserdir[50]="\0"; printf("\033[34minput the new user name:"); scanf("%s",NewAd); printf("\033[34minput the new user passwd:"); scanf("%s",NewAdPwd); strcat(Wadmin,NewAd); strcat(Wadmin,"*"); strcat(Wadmin,NewAdPwd); strcat(Wadmin,"#"); strcat(tuserdir,"./"); strcat(tuserdir,NewAd); if(write(fdUser,Wadmin,strlen(Wadmin)) < 0) { perror(" \033[31mwrite user.txt error\033[0m\n"); exit(1); } else { printf("\033[31madd user success!\n"); } if(mkdir(tuserdir,0777)==-1) { perror("mkdir error:\n"); } } break; case 4: { flag=0; break; } break; } } } break; case 2: /*运行服务器*/ { IsRun=1; printf("\n\033[32mserver is running now\033[0m\n\n"); break; } break; case 3: /*关闭服务器*/ { IsRun=0; printf("\n\033[32mserver is stop now\033[0m\n\n"); break; } break; case 4: { system("clear"); //系统日志 printf("\n\033[31m---------------------System Log---------------------\033[0m\n\n"); FILE *fpLog; if((fpLog = fopen("./log.txt","r")) == NULL) { printf("the log.sys file lost!\n"); } char logInfo[200]; while(fgets(logInfo,200,fpLog)!=NULL) { printf("\n\033[32m%s\033[0m",logInfo); } printf("\n"); printf("\n\033[31m-----------------------Log End-----------------------\033[0m\n\n"); } break; case 5: { IsExit=1; exit(1); } break; } } close(fdMax); close(fdAdmin); close(fdUser); } /*主线程处理函数*/ void mainThread() { int reuse=1; int i=0; signal(SIGPIPE,receivePipBroken); /*------------------------SSL--------------------------------*/ // SSL *ssl; char pwd[100]; char* temp; /* SSL 库初始化 */ SSL_library_init(); /* 载入所有 SSL 算法 */ OpenSSL_add_all_algorithms(); /* 载入所有 SSL 错误消息 */ SSL_load_error_strings(); /* 以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Content Text */ ctx = SSL_CTX_new(SSLv23_server_method()); /* 也可以用 SSLv2_server_method() 或 SSLv3_server_method() 单独表示 V2 或 V3标准 */ if (ctx == NULL) { ERR_print_errors_fp(stdout); exit(1); } /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */ getcwd(pwd,100); if(strlen(pwd)==1) pwd[0]='\0'; if (SSL_CTX_use_certificate_file(ctx, temp=strcat(pwd,"/cacert.pem"), SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stdout); exit(1); } /* 载入用户私钥 */ getcwd(pwd,100); if(strlen(pwd)==1) pwd[0]='\0'; if (SSL_CTX_use_PrivateKey_file(ctx, temp=strcat(pwd,"/privkey.pem"), SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stdout); exit(1); } /* 检查用户私钥是否正确 */ if (!SSL_CTX_check_private_key(ctx)) { ERR_print_errors_fp(stdout); exit(1); } /*------------------------SSL--------------------------------*/ if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0) { fprintf(stderr,"\033[33mSocket error:%s\033[0m\n\a",strerror(errno)); exit(-1); } bzero(&server_addr,sizeof(struct sockaddr_in)); server_addr.sin_family=AF_INET; server_addr.sin_addr.s_addr=htonl(INADDR_ANY); server_addr.sin_port=htons(portnumber); setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(int)); if(bind(sockfd,(struct sockaddr*)(&server_addr),sizeof(struct sockaddr))<0) { fprintf(stderr,"\033[33mBind error:%s\033[0m\n\a",strerror(errno)); exit(1); } if(listen(sockfd, MaxClientNum)==-1) { fprintf(stderr,"\033[33mListen error:%s\033[0m\n\a",strerror(errno)); exit(1); } CreateThreadPool(); /*创建线程池*/ while(1) { if(IsExit==1) /*判断是否退出服务器*/ { int i; printf("\033[31m\nclosing server\n\033[0m"); for(i = 0;i < 60; i += 10) { printf("\033[31m.\033[0m"); fflush(stdout); usleep(100000); } printf("\033[31m\nserver closed\n\033[0m"); pthread_exit(0); } if(IsRun == 1) /*判断服务器是否正常运行*/ { if((new_fd = accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size)) == -1) { perror("accept error!"); exit(-1); } tempsockfd=new_fd; strcpy(clientIP,inet_ntoa(client_addr.sin_addr)); /*保存当前连接客服端IP*/ // if((pthread_create(&id,NULL,(void *)process,&new_fd)) != 0) // { // printf("\033[33mCreate thread error!\033[0m\n"); // } // MoveToBusy(ThreadIdleId[]); pthread_cond_signal(&pthreadCond); // printf("11111111111111111111111111\n"); } } close(sockfd); /* 释放 CTX Start*/ SSL_CTX_free(ctx); /* 释放 CTX End*/ pthread_join(id,NULL); } void process() { // SSL *NewFd=ssl; tap: pthread_mutex_lock(&pthreadMutex); pthread_cond_wait(&pthreadCond,&pthreadMutex); pthread_mutex_unlock(&pthreadMutex); int new_fd=tempsockfd; struct FilePackage sendPackage; SSL *ssl; // SSL_CTX *ctx; // ctx = SSL_CTX_new(SSLv23_server_method()); /* 基于 ctx 产生一个新的 SSL */ ssl = SSL_new(ctx); /* 将连接用户的 socket 加入到 SSL */ SSL_set_fd(ssl, new_fd); /* 建立 SSL 连接 */ if (SSL_accept(ssl) == -1) { perror("accept"); close(new_fd); } SSL *NewFd=ssl; ++CurrentClientNum; if(CurrentClientNum>MaxClientNum) /*客服端连接数达到最大*/ { sendPackage=pack('L'," "," ",0,2,1,""); SSL_write(NewFd,&sendPackage,sizeof(struct FilePackage)); --CurrentClientNum; /* 关闭 SSL 连接 */ SSL_shutdown(NewFd); /* 释放 SSL */ SSL_free(NewFd); close(new_fd); } // printf("~~~~~~~~~~~~~~~~~~~~~~~in~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); while(1) { SSL_read(NewFd,&buff,sizeof(struct FilePackage)); // printf("11111%s",buff.username); // printf("%s\n",&buff); if(buff.cmd == 'Q' && buff.ack == '0') { // close(*NewFd); /* 关闭 SSL 连接 */ SSL_shutdown(NewFd); /* 释放 SSL */ SSL_free(NewFd); // MoveToIdle(); close(new_fd); break; } else { sendPackage=unpack(NewFd,buff); if(sendPackage.cmd!='\0') { SSL_write(NewFd,&sendPackage,sizeof(struct FilePackage)); } } } --CurrentClientNum; goto tap; /* 关闭 SSL 连接 */ // SSL_shutdown(NewFd); // /* 释放 SSL */ // SSL_free(NewFd); // close(new_fd); // close(*NewFd); //pthread_exit(0); } /*解包函数*/ struct FilePackage unpack(SSL *NewFd,struct FilePackage tpack) { struct FilePackage sendPack; char username[20]="\0"; char userpwd[20]="\0"; char *pUser=tpack.buf; char pfilename[125]="\0"; // char userdir[50]="\0"; int filesize; int currentFsize=0; int fd; int fdlog; int flag=1; // printf("2222222%s",tpack.username); switch(tpack.cmd) { case 'L': /*登陆请求*/ { int i=0; while(*pUser!='*') /*从数据包中读取用户帐号与密码*/ { if(i<20) { username[i]=*pUser; ++i; ++pUser; } } ++pUser; i=0; /*跳过*号*/ while(*pUser!='#') { if(i<20) { userpwd[i]=*pUser; ++i; ++pUser; } } // strcat(userdir,"./"); // strcat(userdir,username); // while(flag!=0) // { if(CheckClient(username,userpwd)==1) { /*返回文件列表*/ //getlist(); sendPack = pack('L',"","",0,1,1,""); strcpy(filelist,""); // flag=1; // return sendPack; } else { sendPack=pack('L',"","",0,0,1,""); /*登陆失败*/ // return sendPack; // } } return sendPack; } break; case 'U': { struct statfs statfsbuf; int count=0; currentFsize=0; if(tpack.ack==9) { strcat(pfilename,tpack.username); // printf("111111111111111111%s\n",userdir); strcat(pfilename,"/"); strcat(pfilename,tpack.filename); // printf("22222222222222222222%s\n",pfilename); // printf("%s\n",pfilename); filesize=tpack.filesize; /*文件名已经存在以后实现*/ statfs("./",&statfsbuf); if((statfsbuf.f_bsize*statfsbuf.f_bfree)<=filesize) { printf("\033[31m磁盘空间不足\033[0m\n"); sendPack=pack('U',"","",0,1,1,""); SSL_write(NewFd,&sendPack,sizeof(struct FilePackage)); exit(1); } if((fd=open(pfilename,O_RDWR|O_CREAT,0777))<0) { perror("open error:\n"); } // printf("%d",fd); sendPack=pack('U',"","",0,0,1,""); SSL_write(NewFd,&sendPack,sizeof(struct FilePackage)); if((count=SSL_read(NewFd,&buff,sizeof(struct FilePackage)))==-1) { perror("read error:\n"); } // printf("%s",buff.buf); // printf("0000000000000cmd is:%c ack is:%d",buff.cmd,buff.ack); while(buff.ack==2) { // printf("-----------------%d\n",count); count=buff.filesize; // printf("---------------+%d\n",count); // strncpy(tFileBuf,buff.buf,count); // count=strlen(tFileBuf); // printf("%s\n",tFileBuf); // printf("1111111111cmd is:%c ack is:%d",buff.cmd,buff.ack); if(write(fd,buff.buf,count)==-1) { perror("wirte error:\n"); } if(SSL_read(NewFd,&buff,sizeof(struct FilePackage))==-1) { perror("read error:\n"); } }//文件上传结束 // memset(userdir,'\0',50); /*写入日志*/ char Log[200]="\0"; strcat(Log,""); strcat(Log,"Client IP: "); strcat(Log,clientIP); strcat(Log,"\n"); strcat(Log,"upload Date: "); strcat(Log,getCurrentTime()); strcat(Log,"File Name: "); strcat(Log,pfilename); strcat(Log," \n"); if((fdlog = open("./log.txt",O_WRONLY|O_APPEND)) == -1) { printf("\033[33mlog.sys file open error!\033[0m\n"); exit(-1); } if((write(fdlog,Log,strlen(Log)))<0) { perror("write long.txt error:\n"); exit(-1); } close(fdlog); if(buff.ack==4) { sendPack = pack('U',"","",0,3,1,""); close(fd); } return sendPack; } } break; case 'S': { // printf("33333333%s",tpack.username); getlist(tpack.username); sendPack = pack('S',filelist,"",0,1,strlen(filelist)+1,""); strcpy(filelist,""); return sendPack; } break; case 'D': { int Fd; char buf[1025]={'\0'}; int count=0; struct stat statbuf; char filename[125]="\0"; struct FilePackage data; if(tpack.ack==9) { strcat(filename,tpack.username); strcat(filename,"/"); strcat(filename,tpack.filename); } if(stat(filename,&statbuf)==-1) { sendPack = pack('D',"","",0,8,1,""); return sendPack; } // if(!S_ISREG(statbuf.st_mode)) // { // perror("*"); // } sendPack=pack('D', " ", filename, statbuf.st_size , 0,1,""); SSL_write(NewFd,&sendPack,sizeof(struct FilePackage)); if((Fd=open(filename,O_RDONLY))==-1) { perror("open error: \n"); } while((count=read(Fd,(void *)buf,1024))>0) { sendPack=pack('D', buf, filename, count , 2,count,""); if((SSL_write(NewFd,&sendPack,sizeof(struct FilePackage)))==-1) { perror("send login message:"); } } sendPack=pack('D', " ", filename, statbuf.st_size , 4,1,""); SSL_write(NewFd,&sendPack,sizeof(struct FilePackage)); // printf("senddata\n"); SSL_read(NewFd,&data,sizeof(struct FilePackage)); if(data.cmd == 'D' && data.ack == 3) { sendPack=pack('\0', "", "", 0,8,1,""); close(Fd); } // memset(userdir,'\0',50); /*写入日志*/ char Log[200]="\0"; strcat(Log,""); strcat(Log,"Client IP: "); strcat(Log,clientIP); strcat(Log,"\n"); strcat(Log,"download Date: "); strcat(Log,getCurrentTime()); strcat(Log,"File Name: "); strcat(Log,filename); strcat(Log," \n"); if((fdlog = open("./log.txt",O_WRONLY|O_APPEND)) == -1) { printf("\033[33mlog.txt file open error!\033[0m\n"); exit(-1); } if((write(fdlog,Log,strlen(Log)))<0) { perror("write long.txt error:\n"); exit(-1); } close(fdlog); return sendPack; } break; } } /*获取文件列表*/ void getlist(char *username) { DIR *pdir; struct dirent *pent; char DEFDIR[60]="\0"; strcpy(filelist,""); strcat(DEFDIR,"./"); strcat(DEFDIR,username); // printf("%s",username); if((pdir=opendir(DEFDIR))==NULL) { fprintf(stderr,"open dir error\n"); return; } while(1) { pent=readdir(pdir); if(pent==NULL) { break; } else { strcat(filelist,pent->d_name); strcat(filelist,"\t"); } } closedir(pdir); } /*检测用户名与密码是否正确*/ int CheckClient(char* tUser, char* tPwd) { int flag=1,nflag=1; /*flag为1表示登陆错误,为0表示登陆成功*/ char UN[20]="\0"; char UP[20]="\0"; char *pUser=User; int i=0; while(flag!=0) /*用户员登陆*/ { while(nflag!=0) /*检查用户名是否存在*/ { while(*pUser!='*'&&(*pUser)!='\0') { if(i<20) { UN[i]=*(pUser); ++i; ++pUser; } } ++pUser; /*跳过*号*/ i=0; while(*pUser!='#'&&(*pUser)!='\0') { if(i<20) { UP[i]=*(pUser); ++i; ++pUser; } } ++pUser; /*跳过#号*/ if(strcmp(UN,tUser)==0) { nflag=0; if(strcmp(UP,tPwd)==0) { flag=0; return 1; } else { nflag=1; memset(UP,'\0',20); memset(UN,'\0',20); pUser=User; printf("\n\033[33mUser name or passwd is error!\033[0m\n\n"); i=0; return 0; } } else if(*pUser=='\0') { pUser=User; i=0; memset(UP,'\0',20); memset(UN,'\0',20); printf("\n\033[33mUser name or passwd is error!\033[0m\n\n"); return 0; } i=0; memset(UP,'\0',20); memset(UN,'\0',20); } }//while结束 } /*初始化客服端最大连接数*/ int InitMaxClientNum() { int ReadNum; int fd; char buf[10]; if((fd=open("./maxclientnum.txt",O_RDONLY))<0) { printf("can not open maxclientnum.txt!"); } if((ReadNum=read(fd,buf,10))<0) { printf("can not read from maxclientnum.txt!"); } close(fd); return atoi(buf); } /*初始化管理员和用户*/ void InitAU() { int nRead; int fd; char *pAdmin=Admin; char *pUser=User; int nLeft=1024; /*从admin.txt中读取管理员信息到数组*/ if((fd=open("./admin.txt",O_RDONLY))<0) { printf("can not open admin.txt!"); } while(nLeft>0) /*不断从文件中读取内容直到读取文件中所有内容*/ { if((nRead=read(fd,pAdmin,20))<0) { printf("can not read from admin.txt!"); } else if(nRead==0) { break; } pAdmin+=nRead; nLeft-=nRead; } close(fd); /*从user.txt中读取用户信息到数组*/ if((fd=open("./user.txt",O_RDONLY))<0) { printf("can not open user.txt!"); } while(nLeft>0) { if((nRead=read(fd,pUser,20))<0) { printf("can not read from user.txt!"); } else if(nRead==0) { break; } pUser+=nRead; nLeft-=nRead; } close(fd); } void receivePipBroken(int sign_no) { if(sign_no == SIGPIPE) { printf("\n\033[31ma client exit!\033[0m\n\n"); printf("\n\033[33mplease choose a command:\033[0m\n\n"); CurrentClientNum --; pthread_exit(0); } } /*获取当前时间*/ char *getCurrentTime() { time_t now; struct tm *timenow; time(&now); timenow = localtime(&now); return asctime(timenow); } /*创建线程池*/ void CreateThreadPool() { int i; for(i = 0; i < THREADNUM;++i) { pthread_t tid = 0; pthread_create(&tid,NULL,(void *)process,NULL); ThreadIdleId[TIdleNum]=tid; ++TIdleNum; } } /*线程执行结束后,把自己放入到空闲线程中*/ void MoveToIdle(int tid) { int i=0; int j=0; while(i<=TBusyNum) { if(ThreadBusyId[i]==tid) { //移除此tid在busy数组中 if(i!=TBusyNum) { for(j=i+1;j<=TBusyNum;++j) { ThreadBusyId[j-1]=ThreadBusyId[j]; } } --TBusyNum; break; } ++i; } //把tid增加到idle数组中 ThreadIdleId[TIdleNum]=tid; ++TIdleNum; } /*移入到忙碌线程中去*/ void MoveToBusy(int tid) { int i=0; int j=0; while(i<=TIdleNum) { if(ThreadIdleId[i]==tid) { //移除此tid在busy数组中 if(i!=TIdleNum) { for(j=i+1;j<=TIdleNum;++j) { ThreadIdleId[j-1]=ThreadIdleId[j]; } } --TIdleNum; break; } ++i; } //把tid增加到idle数组中 ThreadBusyId[TBusyNum]=tid; ++TBusyNum; // if(TIdleNum>50) // { // printf("the tidlenum >50\n"); // } } void AddTask(int tid) { TaskId[TaskNum]=tid; ++TaskNum; pthread_cond_signal(&pthreadCond); } client.h #include <stdio.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/stat.h> #include <errno.h> #include <unistd.h> #include <fcntl.h> #include <sys/vfs.h> #include <string.h> #include <pthread.h> #include <openssl/ssl.h> #include <openssl/err.h> #define port 3333 struct FilePackage { char cmd; int filesize; int ack; char username[50]; char filename[125]; char buf[1024]; }; //~~~~~~~~~~~~~~~~~~~~~~~~打包数据~~~~~~~~~~~~~~~~~~~~~~~~~ struct FilePackage pack(char tCmd, char* tBuf, char* tFilename, int tFilesize, int tAck,int count,char *uname) { struct FilePackage tPackage; tPackage.cmd = tCmd; // strcpy(tPackage.buf, tBuf); // strncpy(tPackage.buf, tBuf,1024); memcpy(tPackage.buf,tBuf,count); strcpy(tPackage.filename, tFilename); strcpy(tPackage.username, uname); tPackage.filesize = tFilesize; tPackage.ack = tAck; return tPackage; } /* 请求: Cmd:R 客服端发送数据包:0 请求连接 服务器发送数据包:1答应请求 登陆: Cmd:L 用户名与密码放在buf内以*号隔开如 admin*123 服务器发送数据包的ACK:0 用户名或密码错误 1 登陆成功 2 客户端最大连接数 客服端发送数据包的ACK:9 登陆服务器 下载: Cmd:D 服务器发送数据包的ACK:0 接受下载,返回待下载文件大小 2 开始下载 4 下载完毕 客服端发送数据包的ACK:9 请求下载 1 本地磁盘空间不足 3 接受完毕 上传: Cmd:U 服务器发送数据包的ACK:0 接受上传请求 1 本地磁盘空间不足 3 接收完毕 客服端发送数据包的ACK:9 请求上传,上传文件大小,文件名 2 开始上传文件 4 上传完毕 显示文件列表 Cmd:S 服务器发送数据包的ACK: 0 第一个显示文件列表 客服端发送数据包的ACK:9 请求显示 退出 Cmd: Q 客服端发送数据包的ACK:0 */ client.c #include "client.h" //----------------------处理函数--------------------------- void mainMenu();//主菜单 void log(); //显示log int connectto(int argc,char *args[]); //与服务器建立连接 int login(char username[],char userpasswd[]); //登陆 int senddata(struct FilePackage data); //发送数据包 int recvdata(struct FilePackage *data); //接收数据 void Show(char temp[100]); //显示客户端以及服务器目录 void * UpdateF(void *); //上传文件 void * DownloadF(void *); //下载文件 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~全局变量~~~~~~~~~~~~~~~~~~~~~~~~~~~ char username[50]; char tempuname[50]; char userpasswd[20]; int sockclient; struct sockaddr_in sockaddr1; char ipaddr[15]; SSL_CTX *ctx; SSL *ssl; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void ShowCerts(SSL * ssl) { X509 *cert; char *line; cert = SSL_get_peer_certificate(ssl); if (cert != NULL) { printf("Digital certificate information:\n"); line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); printf("Certificate: %s\n", line); free(line); line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); printf("Issuer: %s\n", line); free(line); X509_free(cert); } else printf("No certificate information!\n"); } //~~~~~~~~~~~~~~~~~~~~~~~显示LOG~~~~~~~~~~~~~~~~~~~~~~~~~~~ void log() { system("clear"); printf(" \033[36m***********\033[0m\033[34mWelcome to Secure File Storage System\033[0m\033[36m***********\n\033[0m"); printf(" \033[36m*\033[0m \033[31m ****** ****** ****** ****** \033[0m \033[36m *\n\033[0m\033[0m"); printf(" \033[36m*\033[0m \033[31m ** * ** ** \033[0m \033[36m *\n\033[0m\033[0m"); printf(" \033[36m*\033[0m \033[31m ***** ****** ***** ***** \033[0m \033[36m *\n\033[0m\033[0m"); printf(" \033[36m*\033[0m \033[31m ** * ** ** \033[0m \033[36m *\n\033[0m\033[0m"); printf(" \033[36m*\033[0m \033[31m ****** * ****** ****** \033[0m \033[34mKJC \033[0m \033[36m*\n\033[0m\033[0m"); printf(" \033[36m***********************************************************\n\033[0m"); sleep(1); } //~~~~~~~~~~~~~~~~~~~~~connect to server~~~~~~~~~~~~~~~~~~~ //成功返回1,失败返回0并且退出 int connectto(int argc,char *args[]) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~判断输入IP是否正确~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int i,count=0; if(argc!=2) { printf("format error: you mast enter ipaddr like this : client 192.168.0.6\n"); exit(0); } for(i=0;*(args[1]+i)!='\0';i++) { if(*(args[1]+i)=='.') count++; } if(count!=3) { printf("IP format error\n"); exit(0); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if((sockclient=socket(AF_INET,SOCK_STREAM,0))==-1) { perror("socket"); exit(0); } memset(&sockaddr1,0,sizeof(sockaddr1)); sockaddr1.sin_family = AF_INET; sockaddr1.sin_addr.s_addr = inet_addr(args[1]); sockaddr1.sin_port = htons(port); if(connect(sockclient,(struct sockaddr* )&sockaddr1,sizeof(sockaddr1))==-1) { perror("connect"); exit(0); } //----------------------------------------------------------------------- /* 基于 ctx 产生一个新的 SSL */ ssl = SSL_new(ctx); SSL_set_fd(ssl, sockclient); /* 建立 SSL 连接 */ if (SSL_connect(ssl) == -1) ERR_print_errors_fp(stderr); else { printf("Connected with %s encryption\n", SSL_get_cipher(ssl)); ShowCerts(ssl); } return 1; } //~~~~~~~~~~~~~~~~~~~~~~~发送数据包~~~~~~~~~~~~~~~~~~~~~~~~ int senddata(struct FilePackage data) { if((SSL_write(ssl,&data,sizeof(struct FilePackage)))==-1) { perror("send login message:"); return 0; } return 1; } //~~~~~~~~~~~~~~~~~~~~~~~接收数据包~~~~~~~~~~~~~~~~~~~~~~~ int recvdata(struct FilePackage *data) { if((SSL_read(ssl,data,sizeof(struct FilePackage)))==-1) { perror("recv login message:"); return 0; } return 1; } //~~~~~~~~~~~~~~~~~~~~~用户登陆~~~~~~~~~~~~~~~~~~~~~~~~~~~ //传送格式username*userpasswd# int login(char username[20],char userpasswd[10]) { top: printf("ID: "); scanf("%s",username); strcpy(tempuname,username); printf("PASSWD: "); scanf("%s",userpasswd); strcat(username,"*"); strcat(username,userpasswd); strcat(username,"#"); // printf("%s\n",username); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ struct FilePackage data; data=pack('L', username, " ", 0, 9,strlen(username),tempuname); // printf("%s\n",username); if(senddata(data)==0) exit(0); // printf("%s\n",username); if(recvdata(&data)==0) exit(0); // printf("%s\n",username); // printf("%s\n",data.buf); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if(data.cmd == 'L' && data.ack == 0) { printf("\n\033[33mUsername or Password error!\033[0m\n\n"); goto top; } if(data.cmd == 'L' && data.ack == 1) { printf("Login Success\n"); printf("%s\n",data.buf); // SSL_shutdown(ssl); // SSL_free(ssl); // close(sockclient); // SSL_CTX_free(ctx); return 1; } if(data.cmd == 'L' && data.ack == 2) { printf("\n\033[32mMaxnum connection!\033[0m\n\n"); exit(0); } return 0; } //~~~~~~~~~~~~~~~~~~~~~~~显示客户端目录~~~~~~~~~~~~~~~~~~~ void Show(char temp[100]) { char command [2]; if((strncpy(command,temp,1),*command)=='1'||(strncpy(command,temp,1),*command)=='2'||(strncpy(command,temp,1),*command)=='3') return; if(strncmp(temp,"cd",2)==0) { char dir[40]={'\0'}; temp[strlen(temp)-1]='\0'; strncpy(dir,(&(*temp)+3),strlen(&(*temp)+3)); /* printf("%d%s",strlen((&(*temp)+3)),(&(*temp)+3)); printf("%d%s",strlen(dir),dir); if(dir[strlen(dir)]=='\0') printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); */ chdir(dir); strcpy(temp,"ls"); } system("clear"); printf("\n\033[34m----------------------------- \033[31mClient Files List \033[34m----------------------------\033[0m\n"); system(temp); // printf("\033[34m*******************************************************************************\033[0m\n"); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~显示服务器目录~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ senddata(pack('S', " ", " ", 0, 9,1,tempuname)); struct FilePackage data; if(recvdata(&data)==0) exit(0); if(data.cmd=='S') { printf("\033[34m----------------------------- \033[31mServer Files List \033[34m----------------------------\033[0m\n"); printf("%s\n",data.buf); printf("\033[34m--------------------------------------------------------------------------------\033[0m\n"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ } //~~~~~~~~~~~~~~~~~~~~~~~上传文件~~~~~~~~~~~~~~~~~~~~~~~~~ void * UpdateF(void *filename) { usleep(500); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ char *Files=(char *)filename; int sockclient; struct sockaddr_in sockaddr1; SSL_CTX *ctx; SSL *ssl; //printf("~2~ %s %d\n",Files,strlen(Files)); if((sockclient=socket(AF_INET,SOCK_STREAM,0))==-1) { perror("socket"); exit(0); } memset(&sockaddr1,0,sizeof(sockaddr1)); sockaddr1.sin_family = AF_INET; sockaddr1.sin_addr.s_addr = inet_addr(ipaddr); sockaddr1.sin_port = htons(port); if(connect(sockclient,(struct sockaddr* )&sockaddr1,sizeof(sockaddr1))==-1) { perror("connect"); exit(0); } //----------------------------------------------------------------------- /* SSL 库初始化 */ // SSL_library_init(); // OpenSSL_add_all_algorithms(); // SSL_load_error_strings(); ctx = SSL_CTX_new(SSLv23_client_method()); if (ctx == NULL) { ERR_print_errors_fp(stdout); exit(1); } /* 基于 ctx 产生一个新的 SSL */ ssl = SSL_new(ctx); SSL_set_fd(ssl, sockclient); /* 建立 SSL 连接 */ if (SSL_connect(ssl) == -1) ERR_print_errors_fp(stderr); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int Fd; char buf[1025]={'\0'}; int count=0; int temp=0; struct stat statbuf; struct FilePackage data; if(stat(Files,&statbuf)==-1) { perror("*"); return 0; } if(!S_ISREG(statbuf.st_mode)) perror("*"); data=pack('U', " ", Files, statbuf.st_size , 9,0,tempuname); if((SSL_write(ssl,&data,sizeof(struct FilePackage)))==-1) perror("send login message:"); if((SSL_read(ssl,&data,sizeof(struct FilePackage)))==-1) { perror("recv login message:"); } if(data.cmd == 'U' && data.ack == 1) { printf("服务器磁盘不足\n"); return 0; } if(data.cmd == 'U' && data.ack == 0) { //do noting; } if((Fd=open(Files,O_RDONLY))==-1) perror("open: "); // printf("~3~ %s %d\n",Files,strlen(Files)); while((count=read(Fd,(void *)buf,1024))>0) { // int i=0; // buf[count]='\0'; // printf("count~~~~~~~~~~~~~~~~~~%d %d\n",count,temp++); // printf("%s\n",buf); // printf("%s",buf); data=pack('U', buf, Files, count , 2,count,tempuname); if((SSL_write(ssl,&data,sizeof(struct FilePackage)))==-1) perror("send login message:"); // printf("~~~~~%s~~~~~~\n",Files); /* int i=0; for(;i<1024;++i) { printf("%c",data.buf[i]); } */ } data=pack('U', " ", Files, statbuf.st_size , 4,1,tempuname); if((SSL_write(ssl,&data,sizeof(struct FilePackage)))==-1) perror("send login message:"); if((SSL_read(ssl,&data,sizeof(struct FilePackage)))==-1) { perror("recv login message:"); } if(data.cmd == 'U' && data.ack == 3) { printf("\n\033[31mUpdate Files over\033[0m\n"); } data=pack('Q', " ", " ", 0 , 9,0,tempuname); if((SSL_write(ssl,&data,sizeof(struct FilePackage)))==-1) perror("send login message:"); close(Fd); close(sockclient); return (void *)1; } //~~~~~~~~~~~~~~~~~~~~~~~下载文件~~~~~~~~~~~~~~~~~~~~~~~~~ void * DownloadF(void *filename) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ char *Files=(char *)filename; int sockclient; struct sockaddr_in sockaddr1; SSL_CTX *ctx; SSL *ssl; usleep(500); //printf("~2~ %s %d\n",Files,strlen(Files)); if((sockclient=socket(AF_INET,SOCK_STREAM,0))==-1) { perror("socket"); exit(0); } memset(&sockaddr1,0,sizeof(sockaddr1)); sockaddr1.sin_family = AF_INET; sockaddr1.sin_addr.s_addr = inet_addr(ipaddr); sockaddr1.sin_port = htons(port); if(connect(sockclient,(struct sockaddr* )&sockaddr1,sizeof(sockaddr1))==-1) { perror("connect"); exit(0); } //----------------------------------------------------------------------- ctx = SSL_CTX_new(SSLv23_client_method()); /* 基于 ctx 产生一个新的 SSL */ ssl = SSL_new(ctx); SSL_set_fd(ssl, sockclient); /* 建立 SSL 连接 */ if (SSL_connect(ssl) == -1) ERR_print_errors_fp(stderr); // else // { // printf("Connected with %s encryption\n", SSL_get_cipher(ssl)); // ShowCerts(ssl); // } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int Fd; char buf[1024]; int count=0; int temp=0; struct statfs statfsbuf; struct FilePackage data; struct stat statbuf; if(stat(Files,&statbuf)==0) { printf("文件重名\n"); return 0; } data=pack('D', " ", Files, 0 , 9,1,tempuname); if((SSL_write(ssl,&data,sizeof(struct FilePackage)))==-1) perror("send login message:"); if((SSL_read(ssl,&data,sizeof(struct FilePackage)))==-1) { perror("recv login message:"); } if(data.cmd == 'D' && data.ack == 0) { statfs("./",&statfsbuf); if((statfsbuf.f_bsize*statfsbuf.f_bfree)<=data.filesize) { printf("\033[31m磁盘空间不足\033[0m\n"); return 0; } } if(data.cmd == 'D' && data.ack == 8) { printf("\033[33mNo such file or directory\033[0m\n"); return 0; } if((Fd=open(Files,O_RDWR|O_CREAT,0777))==-1) perror("open: "); // printf("\033[33mStart Download Files\033[0m\n"); if(SSL_read(ssl,&data,sizeof(struct FilePackage))==-1) { perror("read error:\n"); } while(data.ack==2) { count=data.filesize; if(write(Fd,data.buf,count)==-1) { perror("wirte error:\n"); } if(SSL_read(ssl,&data,sizeof(struct FilePackage))==-1) { perror("read error:\n"); } } if(data.ack==4) { printf("\033[31mDownload Files over\033[0m\n"); data=pack('D', " ", Files, 0 , 3,1,tempuname); if((SSL_write(ssl,&data,sizeof(struct FilePackage)))==-1) perror("send login message:"); data=pack('Q', " ", " ", 0 , 9,0,tempuname); if((SSL_write(ssl,&data,sizeof(struct FilePackage)))==-1) perror("send login message:"); close(sockclient); close(Fd); } return (void *)1; } //~~~~~~~~~~~~~~~~~~~~~~~主菜单~~~~~~~~~~~~~~~~~~~~~~~~~~~ void mainMenu() { char temp[100]; char command [2]; char Files[100]; char Files1[100]; pthread_t pthreadt; strcpy(temp,"ls"); while(1) { int count; int temp1; count=0; temp1=0; if(strncmp(temp,"\n",1)!=0) Show(temp); else goto top; // usleep(500); // printf("\033[34m*****************************\033[31mClient console\033[34m*****************************\033[0m\n"); printf(" \033[34m------------------------------\033[31mClient console\033[34m-----------------------------\033[0m\n"); printf(" \033[34m|\033[0m 1.Update Files 2.Download Files 3.Exit \033[34m|\033[0m\n"); printf(" \033[34m-------------- \033[36mUse \033[31mls \033[36mor \033[31mcd \033[36mto \033[31mdisplayer \033[36mand \033[31mchange dir \033[34m--------------\033[0m\n"); printf(" Please input the Client command:"); top: fgets(temp,sizeof(temp),stdin); switch(strncpy(command,temp,1),*command) { case '1': { printf("\033[33mUpdate Files:\033[0m "); fgets(Files,sizeof(Files),stdin); // printf("%d\n",strlen(Files)); Files[strlen(Files)-1]='\0'; while(Files[count]!='\0' && Files[count]!='\n') { if(Files[count]==' ') { Files[count]='\0'; // printf("~1~ %s\n",&Files[temp1]); pthread_create(&pthreadt,NULL,UpdateF,(void *)&Files[temp1]); temp1=count+1; } count++; } pthread_create(&pthreadt,NULL,UpdateF,(void *)&Files[temp1]); } strcpy(temp,"ls"); break; case '2': { printf("\033[33mDownloadF Files:\033[0m "); fgets(Files1,sizeof(Files1),stdin); Files1[strlen(Files1)-1]='\0'; while(Files1[count]!='\0' && Files1[count]!='\n') { if(Files1[count]==' ') { Files1[count]='\0'; pthread_create(&pthreadt,NULL,DownloadF,(void *)&Files1[temp1]); temp1=count+1; } count++; } pthread_create(&pthreadt,NULL,DownloadF,(void *)&Files1[temp1]); } break; case '3': system("clear"); exit(0); break; } } } int main(int argc,char *args[]) { //---------------------------------------------------------- /* SSL 库初始化 */ SSL_library_init(); OpenSSL_add_all_algorithms(); SSL_load_error_strings(); ctx = SSL_CTX_new(SSLv23_client_method()); if (ctx == NULL) { ERR_print_errors_fp(stdout); exit(1); } //---------------------------------------------------------- strcpy(ipaddr,args[1]); if((connectto(argc,args))!=1) exit(0); if(login(username,userpasswd)==0) { printf("login error"); exit(0); } log(); mainMenu(); return 0; }
线程池示例: thread.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <pthread.h> #include <assert.h> /* *线程池里所有运行和等待的任务都是一个CThread_worker *由于所有任务都在链表里,所以是一个链表结构 */ typedef struct worker { /*回调函数,任务运行时会调用此函数,注意也可声明成其它形式*/ void *(*process) (void *arg); void *arg;/*回调函数的参数*/ struct worker *next; } CThread_worker; /*线程池结构*/ typedef struct { pthread_mutex_t queue_lock; pthread_cond_t queue_ready; /*链表结构,线程池中所有等待任务*/ CThread_worker *queue_head; /*是否销毁线程池*/ int shutdown; pthread_t *threadid; /*线程池中允许的活动线程数目*/ int max_thread_num; /*当前等待队列的任务数目*/ int cur_queue_size; } CThread_pool; int pool_add_worker (void *(*process) (void *arg), void *arg); void *thread_routine (void *arg); static CThread_pool *pool = NULL; void pool_init (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->shutdown = 0; pool->threadid = (pthread_t *) malloc (max_thread_num * sizeof (pthread_t)); int i = 0; for (i = 0; i < max_thread_num; i++) { pthread_create (&(pool->threadid[i]), NULL, thread_routine, NULL); } } /*向线程池中加入任务*/ 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) { 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->max_thread_num; i++) pthread_join (pool->threadid[i], NULL); free (pool->threadid); /*销毁等待队列*/ 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 0x%x\n", pthread_self ()); while (1) { pthread_mutex_lock (&(pool->queue_lock)); /*如果等待队列为0并且不销毁线程池,则处于阻塞状态; 注意 pthread_cond_wait是一个原子操作,等待前会解锁,唤醒后会加锁*/ while (pool->cur_queue_size == 0 && !pool->shutdown) { printf ("thread 0x%x is waiting\n", pthread_self ()); pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock)); } /*线程池要销毁了*/ if (pool->shutdown) { /*遇到break,continue,return等跳转语句,千万不要忘记先解锁*/ pthread_mutex_unlock (&(pool->queue_lock)); printf ("thread 0x%x will exit\n", pthread_self ()); pthread_exit (NULL); } printf ("thread 0x%x is starting to work\n", pthread_self ()); /*assert是调试的好帮手*/ assert (pool->cur_queue_size != 0); assert (pool->queue_head != NULL); /*等待队列长度减去1,并取出链表中的头元素*/ pool->cur_queue_size--; CThread_worker *worker = pool->queue_head; pool->queue_head = worker->next; pthread_mutex_unlock (&(pool->queue_lock)); /*调用回调函数,执行任务*/ (*(worker->process)) (worker->arg); free (worker); worker = NULL; } /*这一句应该是不可达的*/ pthread_exit (NULL); } void * myprocess (void *arg) { printf ("threadid is 0x%x, working on task %d\n", pthread_self (),*(int *) arg); sleep (1);/*休息一秒,延长任务的执行时间*/ return NULL; } int main (int argc, char **argv) { pool_init (3);/*线程池中最多三个活动线程*/ /*连续向池中投入10个任务*/ int *workingnum = (int *) malloc (sizeof (int) * 10); int i; for (i = 0; i < 10; i++) { workingnum[i] = i; pool_add_worker (myprocess, &workingnum[i]); } /*等待所有任务完成*/ sleep (5); /*销毁线程池*/ pool_destroy (); free (workingnum); return 0; }