安全文件传输系统组成: 客户端:用户登录,上传文件,下载文件,浏览文件列表 服务器:用户登录,服务器配置,多线程管理,上传下载管理,系统日志 协议:自定义传输协议 要求: 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]="