题目
简单FTP客户端软件开发(100分)网络环境中的一项基本应用就是将文件从一台计算机中复制到另一台可能相距很远的计算机中。而文件传送协议FTP是因特网上使用得最广泛的文件传送协议。FTP使用客户服务器方式。 设计要求: 1)以命令行形式运行 2)该FTP客户端程序具有以下基本功能:能完成FTP链接的打开和关闭操作;能执行文件的上传和下载;能完成目录的创建、删除等有关操作。 3)设计中加入新的功能:登录,进入上级或下级目录 要求可以传输简单的文本文件。
设计思路
1、分为两个端口,指令交流端口,数据交换端口 2、指令端口连接后一直保持通信,直到获得退出信号 3、数据交换端口在获得相关指令后重新建立连接
使用方法
1、分别创建两个C++项目 2、复制代码进入即可 3、若两个都在本地,使用本地回环测试IP,127.0.0.1 4、登录的部分在客户端中被注释掉了没有开启
Tips:
目前登录以及help部分仍有两个小bug,系由端口的命令断开以及连接部分引起,交由读者自己研究,若不想管可以不使用这两个功能
服务端——>Server
#include "Winsock2.h"
#include "windows.h"
#include <iostream>
#include <string>
using namespace std;
#define RECV_PORT 3312
#define SEND_PORT 4302
#define DATA_PORT 3313
#pragma comment(lib, "wsock32.lib")
SOCKET sockClient, sockServer;
SOCKET dataClient, dataServer;
sockaddr_in dataAddr;
sockaddr_in severAddr;
sockaddr_in ClientAddr;
sockaddr_in dataClientAddr;
int addrLen;
char fileName[20];
char order[20];
char rbuff[1024];
char sbuff[1024];
char namePassword[1024] = "user 123456";
DWORD startSock();
DWORD createSocket();
int sendFileRecord(SOCKET datatcps, WIN32_FIND_DATA *pfd);
int sendFileList(SOCKET datatcps);
int sendFile(SOCKET datatcps, FILE* file);
DWORD connectProcess();
DWORD startSock() {
WSADATA WSAData;
if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0) {
cout << "初始化失败" << endl;
return -1;
}
return 1;
}
DWORD createSocket() {
sockClient = socket(AF_INET, SOCK_STREAM, 0);
dataClient = socket(AF_INET, SOCK_STREAM, 0);
if (sockClient == SOCKET_ERROR||dataClient == SOCKET_ERROR) {
cout << "创建失败" << endl;
WSACleanup();
return -1;
}
dataAddr.sin_family = AF_INET;
severAddr.sin_family = AF_INET;
dataAddr.sin_addr.s_addr = htonl(INADDR_ANY);
dataAddr.sin_port = htons(DATA_PORT);
severAddr.sin_addr.s_addr = htonl(INADDR_ANY);
severAddr.sin_port = htons(RECV_PORT);
if (bind(sockClient, (struct sockaddr FAR*)&severAddr, sizeof(severAddr)) == SOCKET_ERROR||bind(dataClient, (struct sockaddr FAR*)&dataAddr, sizeof(dataAddr)) == SOCKET_ERROR) {
cout << "绑定失败" << endl;
return -1;
}
return 1;
}
DWORD mkdir(char fileName[]){
char path[1000];
GetCurrentDirectory(sizeof(path), path);
strcat(path,"\\");
strcat(path,fileName);
cout<<path<<endl;
bool flag = CreateDirectory(path,NULL);
if (flag)
cout<<"创建文件:"<<fileName<<"成功"<<endl;
else
cout<<"创建文件:"<<fileName<<"失败"<<endl;
}
DWORD delFile(char fileName[]){
char path[1000];
GetCurrentDirectory(sizeof(path), path);
strcat(path,"\\");
strcat(path,fileName);
bool flag = RemoveDirectory(path);
if (flag)
cout<<"删除文件:"<<fileName<<"成功"<<endl;
else
cout<<"删除文件:"<<fileName<<"失败"<<endl;
}
DWORD connectProcess() {
addrLen = sizeof(ClientAddr);
if (listen(sockClient, 10) < 0|| listen(dataClient, 10)<0) {
cout << "监听失败" << endl;
return -1;
}
cout << "服务器正在监听中…" << endl;
while (1) {
sockServer = accept(sockClient, (struct sockaddr FAR*)&ClientAddr, &addrLen);
while (1) {
memset(rbuff, 0, sizeof(rbuff));
memset(sbuff, 0, sizeof(sbuff));
if (recv(sockServer, rbuff, sizeof(rbuff), 0) <= 0) {
continue;
}
cout << endl << "获取并执行的命令:" << rbuff << endl;
if (strncmp(rbuff, "get", 3) == 0) {
strcpy(fileName, rbuff + 4);
FILE* file;
file = fopen(fileName, "rb");
if (file) {
sprintf(sbuff, "get %s", fileName);
if (!send(sockServer, sbuff, sizeof(sbuff), 0)) {
cout<<"发送失败"<<endl;
fclose(file);
return 0;
}
else {
if (!sendFile(dataClient, file)) {
return 0;
}
fclose(file);
}
}else {
strcpy(sbuff, "无法打开文件\n");
cout<<"无法打开文件"<<endl;
if (!send(sockServer, sbuff, sizeof(sbuff), 0)) {
return 0;
}
}
}
else if (strncmp(rbuff, "put", 3) == 0) {
cout<<"debug1"<<endl;
FILE* fd;
int cnt;
strcpy(fileName, rbuff + 4);
fd = fopen(fileName, "wb");
if (fd == NULL) {
cout << "无法打开文件" << fileName << endl;
return 0;
}
sprintf(sbuff, "put %s", fileName);
if (!send(sockServer, sbuff, sizeof(sbuff), 0)) {
fclose(fd);
return 0;
}
memset(sbuff, '\0', sizeof(rbuff));
int dataAddLen = sizeof (dataClientAddr);
dataServer = accept(dataClient, (struct sockaddr FAR*)&dataClientAddr, &dataAddLen);
while ((cnt = recv(dataServer, rbuff, sizeof(rbuff), 0)) > 0) {
fwrite(rbuff, sizeof(char), cnt, fd);
}
cout << "成功获得文件" << fileName << endl;
closesocket(dataServer);
fclose(fd);
}
else if (strncmp(rbuff, "pwd", 3) == 0) {
char path[1000];
GetCurrentDirectory(sizeof(path), path);
strcpy(sbuff, path);
send(sockServer, sbuff, sizeof(sbuff), 0);
}
else if (strncmp(rbuff, "ls", 2) == 0) {
strcpy(sbuff, rbuff);
send(sockServer, sbuff, sizeof(sbuff), 0);
sendFileList(dataClient);
}
else if(strncmp(rbuff, "mkdir", 5)==0){
strcpy(fileName, rbuff + 6);
strcpy(sbuff,rbuff);
send(sockServer, sbuff, sizeof (sbuff),0);
mkdir(fileName);
}
else if(strncmp(rbuff,"del", 3)==0){
strcpy(fileName, rbuff + 4);
strcpy(sbuff,rbuff);
send(sockServer, sbuff, sizeof (sbuff),0);
delFile(fileName);
}
else if (strncmp(rbuff, "cd", 2) == 0) {
strcpy(fileName, rbuff + 3);
strcpy(sbuff, rbuff);
send(sockServer, sbuff, sizeof(sbuff), 0);
char path[1000];
GetCurrentDirectory(sizeof(path), path);
strcat(path,"\\");
strcat(path,fileName);
SetCurrentDirectory(path);
}
else if (strncmp(rbuff, "user", 4) == 0) {
char tbuff[1024];
strcpy(tbuff, rbuff + 5);
strcat(tbuff, " ");
memset(rbuff, '\0', sizeof(rbuff));
strcpy(sbuff, "成功获取用户名\0");
send(sockServer, sbuff, sizeof(sbuff), 0);
recv(sockServer, rbuff, sizeof(rbuff), 0);
cout << endl << "获取并执行的命令:" << rbuff << endl;
strcat(tbuff, rbuff + 5);
if (strcmp(tbuff, namePassword) == 0) {
send(sockServer, "right\0", sizeof(sbuff), 0);
}else {
send(sockServer, "wrong\0", sizeof(sbuff), 0);
}
}
}
closesocket(sockServer);
}
}
int sendFile(SOCKET datatcps, FILE* file) {
int dataAddLen = sizeof (dataClientAddr);
dataServer = accept(datatcps, (struct sockaddr FAR*)&dataClientAddr, &dataAddLen);
cout << "正在发送文件…" << endl;
memset(sbuff, '\0', sizeof(sbuff));
while(1) {
int len = fread(sbuff, 1, sizeof(sbuff), file);
if (send(dataServer, sbuff, len, 0) == SOCKET_ERROR) {
cout << "连接失败" << endl;
closesocket(dataServer);
return 0;
}
if (len < sizeof(sbuff)) {
break;
}
}
closesocket(dataServer);
cout << "发送成功" << endl;
return 1;
}
int sendFileList(SOCKET datatcps) {
int dataAddLen = sizeof (dataClientAddr);
dataServer = accept(datatcps, (struct sockaddr FAR*)&dataClientAddr, &dataAddLen);
HANDLE hff;
WIN32_FIND_DATA fd;
hff = FindFirstFile("*", &fd);
if (hff == INVALID_HANDLE_VALUE) {
const char *errStr = "列出文件列表时发生错误\n";
cout << *errStr << endl;
if (send(dataServer, errStr, strlen(errStr), 0) == SOCKET_ERROR) {
cout << "发送失败" << endl;
}
closesocket(dataServer);
return 0;
}
BOOL flag = TRUE;
while (flag) {
if (!sendFileRecord(dataServer, &fd)) {
closesocket(dataServer);
return 0;
}
flag = FindNextFile(hff, &fd);
}
closesocket(dataServer);
return 1;
}
int sendFileRecord(SOCKET datatcps, WIN32_FIND_DATA *pfd) {
char fileRecord[MAX_PATH + 32];
FILETIME ft;
FileTimeToLocalFileTime(&pfd -> ftLastWriteTime, &ft);
SYSTEMTIME lastWriteTime;
FileTimeToSystemTime(&ft, &lastWriteTime);
const char *dir = pfd -> dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? "<DIR>" : " ";
sprintf(fileRecord, "%04d-%02d-%02d %02d:%02d %5s %10d %-20s\n",
lastWriteTime.wYear,
lastWriteTime.wMonth,
lastWriteTime.wDay,
lastWriteTime.wHour,
lastWriteTime.wMinute,
dir,
pfd -> nFileSizeLow,
pfd -> cFileName
);
if (send(datatcps, fileRecord, strlen(fileRecord), 0) == SOCKET_ERROR) {
cout << "发送失败" << endl;
return 0;
}
return 1;
}
int main(){
if (startSock() == -1 || createSocket() == -1 || connectProcess() == -1) {
return -1;
}
return 1;
}
客户端——>Client
#include <Winsock.h>
#include <windows.h>
#include <time.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define RECV_PORT 3312
#define SEND_PORT 4302
#define DATA_PORT 3313
#pragma comment(lib, "wsock32.lib")
SOCKET sockClient;
sockaddr_in serverAddr;
sockaddr_in dataAddr;
SOCKET dataClient;
char inputIP[20];
char fileName[20];
char rbuff[1024];
char sbuff[1024];
bool checkFlag = false;
DWORD startSock();
DWORD createSocket(SOCKET &mySocket);
DWORD callServer(SOCKET &mySocket,sockaddr_in addr);
int command();
void help();
void list(SOCKET &sockfd);
DWORD sendTCP(char data[]);
int user();
int pass();
int sendFile(SOCKET &datatcps, FILE* file);
DWORD startSock() {
WSADATA WSAData;
char a[20];
memset(a, 0, sizeof(a));
if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0) {
cout << "sock初始化失败" << endl;
return -1;
}
if (strncmp(inputIP, a, sizeof(a)) == 0) {
cout << "请输入要连接的服务器IP:";
cin >> inputIP;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr(inputIP);
serverAddr.sin_port = htons(RECV_PORT);
dataAddr.sin_family = AF_INET;
dataAddr.sin_addr.s_addr = inet_addr(inputIP);
dataAddr.sin_port = htons(DATA_PORT);
return 1;
}
DWORD createSocket(SOCKET &mySocket) {
mySocket = socket(AF_INET, SOCK_STREAM, 0);
if (mySocket == SOCKET_ERROR) {
cout << "创建socket失败" << endl;
WSACleanup();
return -1;
}
return 1;
}
DWORD callServer(SOCKET &mySocket,sockaddr_in addr) {
createSocket(mySocket);
if (connect(mySocket, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
cout << "连接失败" << endl;
memset(inputIP, 0, sizeof(inputIP));
return -1;
}
return 1;
}
void help() {
cout << " ___________________________________________ " << endl
<< " | FTP帮助菜单 | " << endl
<< " | 1、get 下载文件 [输入格式: get 文件名 ] | " << endl
<< " | 2、put 上传文件 [输入格式:put 文件名] | " << endl
<< " | 3、pwd 显示当前文件夹的绝对路径 | " << endl
<< " | 4、ls 显示远方当前目录的文件 | " << endl
<< " | 5、mkdir 新建文件夹 [输入格式:mkdir 文件名] | " << endl
<< " | 6、del 删除文件夹 [输入格式:del 文件名] | " << endl
<< " | 7、cd 改变远方当前目录和路径 | " << endl
<< " | 进入下级目录: cd 路径名 | " << endl
<< " | 进入上级目录: c .. | " << endl
<< " | 8、? 或者 help 进入帮助菜单 | " << endl
<< " | 9、quit 退出FTP | " << endl
<< " |___________________________________________| " << endl;
}
DWORD sendTCP(char data[]) {
int length = send(sockClient, data, strlen(data), 0);
if (length <= 0) {
cout << "发送命令至服务端失败" << endl;
closesocket(sockClient);
WSACleanup();
return -1;
}
return 1;
}
int sendFile(SOCKET &datatcps, FILE* file) {
callServer(datatcps,dataAddr);
cout << "正在传输文件…" << endl;
memset(sbuff, '\0', sizeof(sbuff));
while (1) {
int len = fread(sbuff, 1, sizeof(sbuff), file);
if (send(datatcps, sbuff, sizeof(rbuff), 0) == SOCKET_ERROR) {
cout << "与客户端的连接中断" << endl;
closesocket(datatcps);
return 0;
}
if (len < sizeof(sbuff)) {
break;
}
}
closesocket(datatcps);
cout << "传输完成" << endl;
return 1;
}
void list(SOCKET &sockfd) {
callServer(sockfd,dataAddr);
int nRead;
memset(sbuff, '\0', sizeof(sbuff));
while (1) {
nRead = recv(sockfd, rbuff, sizeof(rbuff), 0);
if (nRead == SOCKET_ERROR) {
cout << "读取时发生错误" << endl;
exit(1);
}
if (nRead == 0) {
break;
}
cout<<"nRead长度"<<nRead<<endl;
rbuff[nRead] = '\0';
cout << rbuff << endl;
}
cout<<"读取结束"<<endl;
closesocket(sockfd);
}
int user() {
char operation[10], name[20];
char order[30] = "\0";
char buff[80];
cout << "请输入用户名指令(user 用户名):";
strcpy(operation,"user");
cin >> name;
strcat(order, operation), strcat(order, " "), strcat(order, name);
sprintf(buff, order);
sendTCP(buff);
recv(sockClient, rbuff, sizeof(rbuff), 0);
cout << rbuff << endl;
return 1;
}
int pass() {
char operation[10], name[20];
char order[30] = "\0";
char buff[80];
cout << "请输入密码指令(pass 密码):" ;
strcpy(operation,"pass");
cin >> name;
strcat(order, operation), strcat(order, " "), strcat(order, name);
sprintf(buff, order);
sendTCP(buff);
recv(sockClient, rbuff, sizeof(rbuff), 0);
cout << rbuff << endl;
if (strcmp(rbuff, "wrong") == 0) {
return 0;
}
return 1;
}
int command(){
char operation[10], name[20];
char order[30] = "\0";
char buff[80];
FILE *fd1, *fd2;
int cnt;
memset(operation, 0, sizeof(operation));
memset(name, 0, sizeof(name));
memset(order, 0, sizeof(order));
memset(buff, 0, sizeof(buff));
memset(rbuff, 0, sizeof(rbuff));
memset(sbuff, 0, sizeof(sbuff));
cout << endl << "请输入要执行的指令: ";
cin >> operation;
if (strncmp(operation, "get", 3) == 0 || strncmp(operation, "put", 3) == 0 ||
strncmp(operation, "cd", 2) == 0 || strncmp(operation, "mkdir", 5) == 0 || strncmp(operation, "del", 3) ==0){
cin >> name;
} else if (strncmp(operation, "quit", 4) == 0) {
cout << "感谢您的使用" << endl;
return 1;
} else if (strncmp(operation, "?", 1) == 0 || strncmp(operation, "help", 4) == 0) {
help();
}else if(strncmp(operation,"ls",2)==0|| strncmp(operation,"pwd",3)==0){
}
else{
cout<<"非法输入"<<endl;
return 0;
}
strcat(order, operation), strcat(order, " "), strcat(order, name);
sprintf(buff, order);
sendTCP(buff);
recv(sockClient, rbuff, sizeof(rbuff), 0);
cout << rbuff << endl;
if (strncmp(rbuff, "get", 3) == 0) {
callServer(dataClient,dataAddr);
fd1 = fopen(name, "wb");
if (fd1 == NULL) {
cout << "打开或者新建 " << name << "文件失败" << endl;
return 1;
}
memset(rbuff, '\0', sizeof(rbuff));
while ((cnt = recv(dataClient, rbuff, sizeof(rbuff), 0)) > 0) {
fwrite(rbuff, sizeof(rbuff), 1, fd1);
}
closesocket(dataClient);
fclose(fd1);
}
else if (strncmp(rbuff, "put", 3) == 0) {
strcpy(fileName, rbuff + 4);
fd2 = fopen(fileName, "rb");
if (fd2) {
if (!sendFile(dataClient, fd2)) {
cout << "发送失败" << endl;
return 1;
}
fclose(fd2);
} else {
strcpy(sbuff, "无法打开文件\n");
if (!send(sockClient, sbuff, sizeof(sbuff), 0)) {
return 1;
}
}
}
else if (strncmp(rbuff, "ls", 2) == 0) {
list(dataClient);
}
return 0;
}
int main() {
while (1) {
startSock();
if (callServer(sockClient,serverAddr) == -1) {
continue;
}
cout << "发送连接请求成功" << endl;
checkFlag = true;
if(checkFlag){
help();
}
while(checkFlag){
if(command()){
break;
}
}
cout<<"命令输入结束"<<endl;
closesocket(sockClient);
WSACleanup();
return 0;
}
}
/*
192.168.0.100
user gyc
pass 123456
pwd
cd Debug
get 110.txt
*/
|