基于C++QT的文件传输协议FTP客户端服务端设计

您所在的位置:网站首页 查看电脑的线程 基于C++QT的文件传输协议FTP客户端服务端设计

基于C++QT的文件传输协议FTP客户端服务端设计

2023-06-06 02:58| 来源: 网络整理| 查看: 265

目录 文件传输协议的简单设计与实现 0 一、 设计目的 0 二、 设计内容和功能 0 1、设计内容 0 2、具体功能 0 三、设计平台与语言 1 四、 设计具体步骤 1 1、 显示当前IP(QT的接口函数实现) 9 2、 当前客户连接数 9 3、 可查看连接客户的ip信息 9 4、 消息提示 9 5、 显示当前工作路径和当前目录的内容 10 6、 可查看服务器磁盘的所有文件 10 7、改变当前工作目录。 10 7、 查看已连接客户的IP 11 1、 命令解析 11 2、 帮助命令”?” 11 六、 课程设计心得 12 七、 参考文献 12 二、设计内容和功能 1、设计内容 我们的计算机网络实验环境建立在TCP/IP 网络体系结构之上。各计算机除了安装TCP/IP 软件外,还安装了TCP/IP 开发系统。实验室各计算机具备Windows环境中套接字socket 的编程接口功能,可为用户提供全网范围的进程通信功能。本设计实现了一个简单的文件传送协议。 2、具体功能 用socket 编程接口编写两个程序,分别为客户程序和服务器程序,该程序应能实现了下述命令功能: get:取远方的一个文件 put:传给远方一个文件 pwd:显示远主当前目录 dir:列出远方当前目录 cd :改变远方当前目录 ? :显示你提供的命令 ls :列出当前目录 quit :退出返回 其中支持多连接,并限制了只能有三个并发客户端。 三、设计平台与语言 平台:LINUX 语言:C 和 C++ 界面设计: qt 四、设计具体步骤 ⑴、总体方案设计: 在这里插入图片描述

服务器: 服务器中一直在阻塞地等待客户端的连接。而每个连接一个客户端就会创建一一条TCP通道,并用一线程和处理这条TCP通道的命令传输。每当需要进行文件传输时,就会再创建一条TCP通道进行文件传输,传输完毕后释放这条通道。 客户端:首先通过TCP连接到服务器产生一条TCP通道,并创建一线程来处理服务发来的信息,然后通过服务器提供的命令和服务器进行交互,当需要获取或上传文件时,再创建一条TCP通道进行文件传输,传输完毕后释放这条通道,且可以保持和服务器进行交互。

#include "ftp_client.h" /******************************************************* *功能: * get:取远方的一个文件 * put:传给远方一个文件 * pwd:显示远主当前目录 * dir:列出远方当前目录 * cd :改变远方当前目录 * ? :显示你提供的命令 * ls :显示本地目录 * quit:退出返回 * *********************************************************/ /******************上传文件到服务器*******************/ int put_file(char *file) { int ffd; //file 文件描述符 char buf[256]; //缓存区 int total_c; //文件总大小 int sent_c = 0; //已经发送的字节数 int snd_c; //发送字节数 int ret; //处理返回值 int ack; //信号确认 /*打开要发送的文件*/ ffd = open(file, O_RDONLY); if(ffd == -1) { printf("open %s failled\n", file); goto SNDERR; } /*发送READY_T的信号*/ ack = READY_T; ret = send(datafd, &ack, 4, 0); /*等待对方发送确认的应答*/ ret = recv(datafd, &ack, 4, MSG_WAITALL); if(ack == FAILL_T) goto SNDERR; /*发送文件总大小*/ total_c = lseek(ffd, 0, SEEK_END); lseek(ffd, 0, SEEK_SET); printf("have %.2f KB to send\n", (float)total_c/1024); ret = send(datafd, &total_c, sizeof(total_c), 0); /*开始发送文件*/ printf("sending %s .......\n", file); snd_c = 255; while(1) { bzero(buf, sizeof(buf)); //从文件中读取snd_c字节到缓存 ret = read(ffd, &buf, snd_c); //发送snd_c个字节 ret = send(datafd, buf, snd_c, 0); //总字节数-已发送字节数 total_c -= ret; sent_c += ret; if(total_c < snd_c) snd_c = total_c; if(total_c 0) { //把接收到的数据写入文件 write(ffd, buf, ret); //总大小-接收到的字节数 file_c -= ret; //更新收到的总数 got_c += ret; } else if(ret == 0) { printf("download %s success\n", file); break; } else if(ret == -1) { printf("internet err!\n"); break; } } /*等待发送完毕确认信号*/ ret = recv(datafd, &ack, 4, 0); ack = OK_T; /*发送以接收完毕确认信号*/ ret = send(datafd, &ack, 4, 0); printf("download %.2f KB\n", (float)got_c/1024); close(ffd); return 0; //错误处理 RECVERR: //打印错误信息 perror("download err"); //发送接收错误信号 ack = FAILL_T; ret = send(datafd, &ack, 4, 0); //关闭文件 close(ffd); return -1; } /******************显示帮助信息*******************/ void show_help() { printf("================帮助命令==================\n"); printf(" ==get 下载文件==\n ==put 上传文件== \ \n ==dir 列出远方当前目录==\n ==pwd 显示远主当前目录==\ \n ==cd 列出远方当前目录==\n ==? 显示命令帮助==\ \n ==ls 列出本地目录==\n ==quit 退出==\n"); printf("==========================================\n"); } /******************解释命令*******************/ int get_cmd(char *msg) { int cmd = -1; if(strncmp(msg, "get", 3) == 0 || strncmp(msg, "GET", 3) == 0) cmd = GET; else if(strncmp(msg, "put", 3) == 0 || strncmp(msg, "PUT", 3) == 0) cmd = PUT; else if(strncmp(msg, "pwd", 3) == 0 || strncmp(msg, "PWD", 3) == 0) cmd = PWD; else if(strncmp(msg, "dir", 3) == 0 || strncmp(msg, "DIR", 3) == 0) cmd = GDIR; else if(strncmp(msg, "cd", 2) == 0 || strncmp(msg, "cd", 2) == 0) cmd = CD; else if(strncmp(msg, "?", 1) == 0 ) cmd = HELP; else if(strncmp(msg, "ls", 2) == 0 || strncmp(msg, "LS", 2) == 0) cmd = LS; else if(strncmp(msg, "quit",4) == 0 || strncmp(msg, "QUIT", 4) == 0) cmd = QUIT; else if(strcmp(msg, "q") == 0 || strcmp(msg, "Q") == 0) cmd = QUIT; else printf("command not found (? for help)\n"); return cmd; } /*******************文件传输的线程********************/ void *transfer_routine(void *arg) { //判断发送还是接收 switch(flag) { case PUT: //发送文件 put_file(file_name); break; case GET: //接收文件 dowload(file_name); break; } //输入提示 write(0,"myftp>", sizeof("myftp>")); } /*******************接收并显示服务当前目录的内容********************/ void get_dir() { int r = 1; //初始接收一个字节 int get_c = 0; //已经接收的字节数 char r_buf[256]; //接收到完整的文件名缓存 char temp_buf[256]; //接收缓存区 //清空缓存 bzero(r_buf, sizeof(r_buf)); while(1) { //清空缓存 bzero(temp_buf, sizeof(temp_buf)); //接收,由于tcp是字节流,因此先接收文件名长度,再接收完整的文件名 r = recv(fd, temp_buf, r, MSG_WAITALL); //更新已接收的字节数 get_c += r; //更新已接收的字节数 strcat(r_buf, temp_buf); //要接收的字节数为0时,则结束 if(r_buf[0] == 0) break; //判断是否已经完整接收到一个文件名 if((char)get_c != r_buf[0]) { r = (int)r_buf[0]-get_c; continue; } r_buf[get_c] = '\0'; r_buf[0] = '*'; //打印 printf("%s\n", r_buf); //初始化 bzero(r_buf, sizeof(r_buf)); get_c = 0; r = 1; } printf("===================================\n"); //输入提示 write(0,"myftp>", sizeof("myftp>")); } /******************接收服务器信息线程*******************/ void *rec_msg(void *arg) { char r_buf[256]; //接收缓存 int r; //返回值处理 pthread_t tid; //线程id int *ack = (int *)r_buf; while(1) { //清空缓存 bzero(r_buf, sizeof(r_buf)); //接收 r = recv(fd, r_buf, 255, 0); if(r == -1) { perror("recv fialed"); continue; } r_buf[r] = '\0'; //判断工作方式 switch(flag) { case GET: //下载文件 if(*ack == READY_T) { printf("ready to dowload\n"); pthread_create(&tid, NULL, &transfer_routine, NULL); } is_data = 0; break; case PUT: //上传文件 if(*ack == READY_T) { printf("ready to sent\n"); pthread_create(&tid, NULL, &transfer_routine, NULL); } is_data = 0; break; case GDIR: //获取目录内容 printf("\n"); get_dir(); break; case PWD: //当前路径 printf("%s\n", r_buf); //输入提示 write(0,"myftp>", sizeof("myftp>")); break; case CD: //改变当前路径 printf("%s\n", r_buf); //输入提示 write(0,"myftp>", sizeof("myftp>")); break; } } } /***********等待数据TCP连接***************/ void *data_routine(void *arg) { socklen_t len; len = sizeof(data_adr); while(1) { //等待服务器连接 datafd = accept(dfd, (struct sockaddr *)&(data_adr), &len); is_data = 1; } } /******************列出当前目录的文件及目录*******************/ int ls_dir() { DIR *dp = opendir("./"); struct dirent *ep; int r; char type[104] = "---"; if(dp == NULL) { perror("opendir() failed"); return -1; } errno = 0; while(1) { ep = readdir(dp); if(ep == NULL && errno == 0) { break; } else if(ep == NULL) { perror("readdir() failed"); return -1; } if(ep->d_name[0] == '.') { continue; } bzero(type, sizeof(type)); type[0] = '*'; if(ep->d_type == DT_DIR) type[1] = 'd'; else type[1] = '-'; type[2] = '-'; type[3] = '-'; strncat(type, ep->d_name, strlen(ep->d_name)+5); printf("%s\n", type); if(r == -1) perror("send err"); } closedir(dp); return 0; } /****释放资源,退出******/ void quit() { shutdown(datafd, SHUT_RDWR); shutdown(fd, SHUT_RDWR); close(datafd); close(fd); exit(0); } /**** 控制台命令输入 ******/ void cmd_console() { int r; //处理返回值 char s_buf[256]; //缓存区 char *sent_buf = s_buf; int local_cmd = 0; while(1) { //清空缓存 bzero(s_buf, sizeof(s_buf)); //输入提示 write(0,"myftp>", sizeof("myftp>")); //从终端输入命令 gets(s_buf); if(s_buf[0] == '\0') continue; //处理输入的命令,判断命令类型 switch(get_cmd(s_buf)) { case GET: //下载文件 if(strlen(s_buf) < 5) { printf("pls input get \n"); break; } //跳过get三个字符 sent_buf += 3; //设置传输文件名 strcpy(file_name, sent_buf+1); printf("%s\n",file_name); //设置工作模式为下载文件 flag = GET; //设置第一个字符为命令编号 sent_buf[0] = (char) flag; break; case PUT: //上传文件 if(strlen(s_buf) < 5) { printf("pls input put \n"); break; } //跳过put三个字符 sent_buf += 3; //设置传输文件名 strcpy(file_name, sent_buf+1); //设置工作模式为上传文件 flag = PUT; sent_buf[0] = (char) flag; break; case GDIR: //获取目录内容 flag = GDIR; printf("=========服务器当前目录文件=========\n"); sent_buf[0] = (char) flag; sent_buf[1] = '\0'; break; case PWD: //获取当前路径 flag = PWD; //发送命令给服务器 sent_buf[0] = (char) flag; sent_buf[1] = '\0'; //r = send(fd, s_buf, strlen(s_buf), 0); break; case CD: //改变当前路径 flag = CD; sent_buf += 2; sent_buf[0] = (char) flag; break; case HELP: //显示命令帮助信息 show_help(); local_cmd = 1; break; case LS: printf("=========本地当前目录文件=========\n"); ls_dir(); printf("=================================\n"); local_cmd = 1; break; case QUIT: //退出 quit(); break; default: break; } if(!local_cmd) { //发送命令给服务器 r = send(fd, sent_buf, strlen(sent_buf), 0); //指回缓存区的开头 sent_buf = s_buf; } local_cmd = 0; } } /******************主函数*******************/ int main(int argc, char const *argv[]) { /***默认服务器IP地址*****/ char sip[20] = "192.168.1.210"; int r; //处理返回值 pthread_t tid; //线程id int ack; int data_port = 31629; //数据传输端口 if(argc < 2) { printf("pls input: %s [ip]\n", argv[0]); exit(0); } flag = -1; //工作模式初始化为无 is_data = 0; port = 2121; //默认端口为2121 if(argc > 2) { //自己本地定义端口 int n = strlen(argv[2]); int i; data_port = 0; for( i=0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3