溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C++如何實(shí)現(xiàn)簡單FTP客戶端軟件開發(fā)

發(fā)布時(shí)間:2022-08-04 10:18:39 來源:億速云 閱讀:204 作者:iii 欄目:開發(fā)技術(shù)

本文小編為大家詳細(xì)介紹“C++如何實(shí)現(xiàn)簡單FTP客戶端軟件開發(fā)”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“C++如何實(shí)現(xiàn)簡單FTP客戶端軟件開發(fā)”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識(shí)吧。

題目

簡單FTP客戶端軟件開發(fā)(100分)網(wǎng)絡(luò)環(huán)境中的一項(xiàng)基本應(yīng)用就是將文件從一臺(tái)計(jì)算機(jī)中復(fù)制到另一臺(tái)可能相距很遠(yuǎn)的計(jì)算機(jī)中。而文件傳送協(xié)議FTP是因特網(wǎng)上使用得最廣泛的文件傳送協(xié)議。FTP使用客戶服務(wù)器方式。

設(shè)計(jì)要求:

1)以命令行形式運(yùn)行
2)該FTP客戶端程序具有以下基本功能:能完成FTP鏈接的打開和關(guān)閉操作;能執(zhí)行文件的上傳和下載;能完成目錄的創(chuàng)建、刪除等有關(guān)操作。
3)設(shè)計(jì)中加入新的功能:登錄,進(jìn)入上級(jí)或下級(jí)目錄
要求可以傳輸簡單的文本文件。

設(shè)計(jì)思路

1、分為兩個(gè)端口,指令交流端口,數(shù)據(jù)交換端口
2、指令端口連接后一直保持通信,直到獲得退出信號(hào)
3、數(shù)據(jù)交換端口在獲得相關(guān)指令后重新建立連接

使用方法

1、分別創(chuàng)建兩個(gè)C++項(xiàng)目
2、進(jìn)入即可
3、若兩個(gè)都在本地,使用本地回環(huán)測試IP,127.0.0.1
4、登錄的部分在客戶端中被注釋掉了沒有開啟

Tips:

目前登錄以及help部分仍有兩個(gè)小bug,系由端口的命令斷開以及連接部分引起,交由讀者自己研究,若不想管可以不使用這兩個(gè)功能

服務(wù)端——>Server

#include "Winsock2.h"
#include "windows.h"
#include <iostream>
#include <string>
using namespace std;

#define RECV_PORT 3312    //接收端口
#define SEND_PORT 4302    //發(fā)送端口
#define DATA_PORT 3313  //數(shù)據(jù)發(fā)送端口
#pragma comment(lib, "wsock32.lib")

SOCKET sockClient, sockServer;
SOCKET dataClient, dataServer;

sockaddr_in dataAddr;
sockaddr_in severAddr;//服務(wù)器地址
sockaddr_in ClientAddr;//客戶端地址
sockaddr_in dataClientAddr;//數(shù)據(jù)地址

int addrLen;        //地址長度
char fileName[20];    //文件名
char order[20];        //命令
char rbuff[1024];    //接收緩沖區(qū)
char sbuff[1024];    //發(fā)送緩沖區(qū)

char namePassword[1024] = "user 123456";    //用戶名和密碼

//***************函數(shù)聲明***************

DWORD startSock();
DWORD createSocket();
int sendFileRecord(SOCKET datatcps, WIN32_FIND_DATA *pfd);
int sendFileList(SOCKET datatcps);
int sendFile(SOCKET datatcps, FILE* file);
DWORD connectProcess();

//***************函數(shù)聲明***************
DWORD startSock() {//初始化winsock
    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 << "創(chuàng)建失敗" << endl;
        WSACleanup();
        return -1;
    }
    dataAddr.sin_family = AF_INET;
    severAddr.sin_family = AF_INET;
    dataAddr.sin_addr.s_addr = htonl(INADDR_ANY);//監(jiān)聽任意地址
    dataAddr.sin_port = htons(DATA_PORT);
    severAddr.sin_addr.s_addr = htonl(INADDR_ANY);//監(jiān)聽任意地址
    //cout<<htonl(INADDR_ANY)<<endl;
    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) {
        //bind函數(shù)用于將socket和地址結(jié)構(gòu)綁定==
        cout << "綁定失敗" << endl;
        return -1;
    }
    return 1;
}

DWORD mkdir(char fileName[]){
    char path[1000];
    GetCurrentDirectory(sizeof(path), path);//找到當(dāng)前進(jìn)程的當(dāng)前目錄

    strcat(path,"\\");
    strcat(path,fileName);
    cout<<path<<endl;
    bool flag = CreateDirectory(path,NULL);
    if (flag)
        cout<<"創(chuàng)建文件:"<<fileName<<"成功"<<endl;
    else
        cout<<"創(chuàng)建文件:"<<fileName<<"失敗"<<endl;

}

DWORD delFile(char fileName[]){
    char path[1000];
    GetCurrentDirectory(sizeof(path), path);//找到當(dāng)前進(jìn)程的當(dāng)前目錄

    strcat(path,"\\");
    strcat(path,fileName);
   // cout<<path<<endl;
    bool flag = RemoveDirectory(path);
    if (flag)
        cout<<"刪除文件:"<<fileName<<"成功"<<endl;
    else
        cout<<"刪除文件:"<<fileName<<"失敗"<<endl;
}
DWORD connectProcess() {
    addrLen = sizeof(ClientAddr);//addrLen是對(duì)象地址的長度

    if (listen(sockClient, 10) < 0|| listen(dataClient, 10)<0) {//讓套接字進(jìn)入被動(dòng)監(jiān)聽狀態(tài),參數(shù)2為請(qǐng)求隊(duì)列的最大長度
        cout << "監(jiān)聽失敗" << endl;
        return -1;
    }
    cout << "服務(wù)器正在監(jiān)聽中…" << endl;
    while (1) {
        //accept取出隊(duì)列頭部的連接請(qǐng)求
        //sockclient是處于監(jiān)聽的套接字
        //ClientAddr 是監(jiān)聽的對(duì)象地址

        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 << "獲取并執(zhí)行的命令:" << rbuff << endl;
            if (strncmp(rbuff, "get", 3) == 0) {//將文件發(fā)給客戶端
                strcpy(fileName, rbuff + 4);
                FILE* file;//定義一個(gè)文件訪問指針
                //處理下載文件請(qǐng)求
                file = fopen(fileName, "rb");//二進(jìn)制打開文件,只允許讀
                if (file) {
                    sprintf(sbuff, "get %s", fileName);
                    if (!send(sockServer, sbuff, sizeof(sbuff), 0)) {
                        cout<<"發(fā)送失敗"<<endl;
                        fclose(file);
                        return 0;
                    }
                    else {//創(chuàng)建額外數(shù)據(jù)連接傳送數(shù)據(jù)
                        if (!sendFile(dataClient, file)) {
                            return 0;
                        }
                        fclose(file);
                    }
                }else {
                    strcpy(sbuff, "無法打開文件\n");
                    cout<<"無法打開文件"<<endl;
                    if (!send(sockServer, sbuff, sizeof(sbuff), 0)) {
                        return 0;
                    }
                }
            }//get
            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);//把cnt個(gè)數(shù)據(jù)長度為char的數(shù)據(jù)從rbuff輸入到fd指向的文件
                }
                cout << "成功獲得文件" << fileName << endl;
                closesocket(dataServer);
                fclose(fd);
            }//put
            else if (strncmp(rbuff, "pwd", 3) == 0) {
                char path[1000];
                GetCurrentDirectory(sizeof(path), path);//找到當(dāng)前進(jìn)程的當(dāng)前目錄
                strcpy(sbuff, path);
                send(sockServer, sbuff, sizeof(sbuff), 0);
            }//pwd
            else if (strncmp(rbuff, "ls", 2) == 0) {
                strcpy(sbuff, rbuff);
                send(sockServer, sbuff, sizeof(sbuff), 0);
                sendFileList(dataClient);
            }//dir
            else if(strncmp(rbuff, "mkdir", 5)==0){
                strcpy(fileName, rbuff + 6);
                strcpy(sbuff,rbuff);
                send(sockServer, sbuff, sizeof (sbuff),0);//發(fā)送回信息
                mkdir(fileName);
            }//mkdir
            else if(strncmp(rbuff,"del", 3)==0){
                strcpy(fileName, rbuff + 4);//獲得要?jiǎng)h的文件名
                strcpy(sbuff,rbuff);
                send(sockServer, sbuff, sizeof (sbuff),0);//發(fā)送回信息
                delFile(fileName);
            }//del
            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);//找到當(dāng)前進(jìn)程的當(dāng)前目錄
                strcat(path,"\\");
                strcat(path,fileName);
                SetCurrentDirectory(path);//設(shè)置當(dāng)前目錄
            }//cd
            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 << "獲取并執(zhí)行的命令:" << rbuff << endl;
                strcat(tbuff, rbuff + 5);
                if (strcmp(tbuff, namePassword) == 0) {//驗(yàn)證是否正確并返回?cái)?shù)據(jù)給客戶端
                    send(sockServer, "right\0", sizeof(sbuff), 0);
                }else {
                    send(sockServer, "wrong\0", sizeof(sbuff), 0);
                }
            }//user pass

        }
        closesocket(sockServer);
    }
}
int sendFile(SOCKET datatcps, FILE* file) {
    int dataAddLen = sizeof (dataClientAddr);
    dataServer = accept(datatcps, (struct sockaddr FAR*)&dataClientAddr, &dataAddLen);
    cout << "正在發(fā)送文件…" << endl;
    memset(sbuff, '\0', sizeof(sbuff));
    while(1) {//從文件中循環(huán)讀取數(shù)據(jù)并發(fā)送至客戶端
        int len = fread(sbuff, 1, sizeof(sbuff), file);//把file指針指向的文件中的內(nèi)容讀取到sbuff中
       //cout<<"sbuff內(nèi)容:"<<sbuff<<endl;
        if (send(dataServer, sbuff, len, 0) == SOCKET_ERROR) {
            cout << "連接失敗" << endl;
            closesocket(dataServer);
            return 0;
        }
        if (len < sizeof(sbuff)) {//文件傳送結(jié)束
            break;
        }
    }
    closesocket(dataServer);
    cout << "發(fā)送成功" << endl;
    return 1;
}
int sendFileList(SOCKET datatcps) {
    int dataAddLen = sizeof (dataClientAddr);
    dataServer = accept(datatcps, (struct sockaddr FAR*)&dataClientAddr, &dataAddLen);
    HANDLE hff;                                //建立一個(gè)線程
    WIN32_FIND_DATA fd;                        //搜索文件
    hff = FindFirstFile("*", &fd);            //查找文件來把待操作文件的相關(guān)屬性讀取到WIN32_FIND_DATA結(jié)構(gòu)中去
    if (hff == INVALID_HANDLE_VALUE) {        //發(fā)生錯(cuò)誤
        const char *errStr = "列出文件列表時(shí)發(fā)生錯(cuò)誤\n";
        cout << *errStr << endl;
        if (send(dataServer, errStr, strlen(errStr), 0) == SOCKET_ERROR) {
            cout << "發(fā)送失敗" << endl;
        }
        closesocket(dataServer);
        return 0;
    }
    BOOL flag = TRUE;
    while (flag) {//發(fā)送文件信息

        if (!sendFileRecord(dataServer, &fd)) {
            closesocket(dataServer);
            return 0;
        }
        flag = FindNextFile(hff, &fd);//查找下一個(gè)文件
    }
    closesocket(dataServer);
    return 1;
}
int sendFileRecord(SOCKET datatcps, WIN32_FIND_DATA *pfd) {//發(fā)送當(dāng)前的文件記錄
    char fileRecord[MAX_PATH + 32];

    FILETIME ft;                        //文件的建立時(shí)間
    FileTimeToLocalFileTime(&pfd -> ftLastWriteTime, &ft);//Converts a file time to a local file time.

    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) {
        //通過datatcps接口發(fā)送fileRecord數(shù)據(jù),成功返回發(fā)送的字節(jié)數(shù)
        cout << "發(fā)送失敗" << endl;
        return 0;
    }
    return 1;
}
int main(){

    if (startSock() == -1 || createSocket() == -1 || connectProcess() == -1) {
        return -1;
    }
    return 1;
}

客戶端&mdash;&mdash;>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    //發(fā)送端口
#define DATA_PORT 3313  //數(shù)據(jù)接受端口

#pragma comment(lib, "wsock32.lib")    //加載ws2_32.dll,它是Windows Sockets應(yīng)用程序接口, 用于支持Internet和網(wǎng)絡(luò)應(yīng)用程序。

SOCKET sockClient;        //客戶端對(duì)象
sockaddr_in serverAddr;    //服務(wù)器地址
sockaddr_in dataAddr;
SOCKET dataClient;      //數(shù)據(jù)對(duì)象

char inputIP[20];        //存儲(chǔ)輸入的服務(wù)器IP
char fileName[20];        //文件名
char rbuff[1024];        //接收緩沖區(qū)
char sbuff[1024];        //發(fā)送緩沖區(qū)
bool checkFlag = false;            //標(biāo)志是否通過登陸

//***********************函數(shù)聲明***********************
DWORD startSock();                            //啟動(dòng)winsock并初始化
DWORD createSocket(SOCKET &mySocket);                        //創(chuàng)建socket
DWORD callServer(SOCKET &mySocket,sockaddr_in addr);                            //發(fā)送連接請(qǐng)求

int command();                             //執(zhí)行命令
void help();                                //菜單
void list(SOCKET &sockfd);                    //列出遠(yuǎn)方當(dāng)前目錄
DWORD sendTCP(char data[]);                    //發(fā)送要執(zhí)行的命令至服務(wù)端
int user();                                    //上傳用戶名
int pass();                                    //上傳密碼
int sendFile(SOCKET &datatcps, FILE* file);    //put 傳送給遠(yuǎn)方一個(gè)文件
//***********************函數(shù)聲明***********************


//***********************函數(shù)定義***********************
DWORD startSock() { //啟動(dòng)winsock并初始化
    WSADATA WSAData;
    char a[20];
    memset(a, 0, sizeof(a));
    if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0) { //加載winsock版本
        cout << "sock初始化失敗" << endl;
        return -1;
    }
    if (strncmp(inputIP, a, sizeof(a)) == 0) {
        cout << "請(qǐng)輸入要連接的服務(wù)器IP:";
        cin >> inputIP;
    }
    //設(shè)置地址結(jié)構(gòu)
    serverAddr.sin_family = AF_INET;                    //表明底層是使用的哪種通信協(xié)議來遞交數(shù)據(jù)的,AF_INET表示使用 TCP/IPv4 地址族進(jìn)行通信
    serverAddr.sin_addr.s_addr = inet_addr(inputIP);    //指定服務(wù)器IP,十進(jìn)制轉(zhuǎn)化成二進(jìn)制IPV4地址
    serverAddr.sin_port = htons(RECV_PORT);                //設(shè)置端口號(hào),htons用于將主機(jī)字節(jié)序改為網(wǎng)絡(luò)字節(jié)序

    dataAddr.sin_family = AF_INET;
    dataAddr.sin_addr.s_addr = inet_addr(inputIP);
    dataAddr.sin_port = htons(DATA_PORT);//數(shù)據(jù)端口和控制端口不一樣

    return 1;
}
DWORD createSocket(SOCKET &mySocket) { //創(chuàng)建socket
    //要使用套接字,首先必須調(diào)用socket()函數(shù)創(chuàng)建一個(gè)套接字描述符,就如同操作文件時(shí),首先得調(diào)用fopen()函數(shù)打開一個(gè)文件。
    mySocket = socket(AF_INET, SOCK_STREAM, 0);//當(dāng)scoket函數(shù)成功調(diào)用時(shí)返回一個(gè)新的SOCKET(Socket Descriptor) //SOCK_STREAM(流式套接字):Tcp連接,提供序列化的、可靠的、雙向連接的字節(jié)流。支持帶外數(shù)據(jù)傳輸
    if (mySocket == SOCKET_ERROR) {
        cout << "創(chuàng)建socket失敗" << endl;
        WSACleanup();//終止Ws2_32.dll 的使用
        return -1;
    }
    return 1;
}
DWORD callServer(SOCKET &mySocket,sockaddr_in addr) { //發(fā)送連接請(qǐng)求
    createSocket(mySocket);
    if (connect(mySocket, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {//connect()創(chuàng)建與指定外部端口的連接
        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 顯示當(dāng)前文件夾的絕對(duì)路徑                |    " << endl
         << "       | 4、ls 顯示遠(yuǎn)方當(dāng)前目錄的文件                 |   " << endl
         << "       | 5、mkdir 新建文件夾 [輸入格式:mkdir 文件名]   |   " << endl
         << "       | 6、del 刪除文件夾 [輸入格式:del 文件名]       |   " << endl
         << "       | 7、cd  改變遠(yuǎn)方當(dāng)前目錄和路徑                 |   " << endl
         << "       |         進(jìn)入下級(jí)目錄: cd 路徑名              |   " << endl
         << "       |         進(jìn)入上級(jí)目錄: c ..                  |   " << endl
         << "       | 8、? 或者 help 進(jìn)入幫助菜單                  |   " << endl
         << "       | 9、quit 退出FTP                            |   " << endl
         << "       |___________________________________________|    " << endl;
}
DWORD sendTCP(char data[]) { //發(fā)送要執(zhí)行的命令至服務(wù)端
    int length = send(sockClient, data, strlen(data), 0);
    if (length <= 0) {
        cout << "發(fā)送命令至服務(wù)端失敗" << endl;
        closesocket(sockClient);//當(dāng)不使用socket()創(chuàng)建的套接字時(shí),應(yīng)該調(diào)用closesocket()函數(shù)將它關(guān)閉,就如同調(diào)用fclose()函數(shù)關(guān)閉一個(gè)文件,用來進(jìn)行套接字資源的釋放。
        WSACleanup();
        return -1;
    }
    return 1;
}
int sendFile(SOCKET &datatcps, FILE* file) { //put 傳送給遠(yuǎn)方一個(gè)文件
    callServer(datatcps,dataAddr);
    cout << "正在傳輸文件…" << endl;
    memset(sbuff, '\0', sizeof(sbuff));
    while (1) { //從文件中循環(huán)讀取數(shù)據(jù)并發(fā)送
        int len = fread(sbuff, 1, sizeof(sbuff), file); //fread從file文件讀取sizeof(sbuff)長度的數(shù)據(jù)到sbuff,返回成功讀取的數(shù)據(jù)個(gè)數(shù)

        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) { //列出遠(yuǎn)方當(dāng)前目錄
    callServer(sockfd,dataAddr);
    int nRead;
    memset(sbuff, '\0', sizeof(sbuff));
    while (1) {
        nRead = recv(sockfd, rbuff, sizeof(rbuff), 0);
        //recv通過sockClient套接口接受數(shù)據(jù)存入rbuff緩沖區(qū),返回接收到的字節(jié)數(shù)
        if (nRead == SOCKET_ERROR) {
            cout << "讀取時(shí)發(fā)生錯(cuò)誤" << endl;
            exit(1);
        }
        if (nRead == 0) { //數(shù)據(jù)讀取結(jié)束
            break;
        }
        cout<<"nRead長度"<<nRead<<endl;
        //顯示數(shù)據(jù)
        rbuff[nRead] = '\0';
        cout << rbuff << endl;
    }
    cout<<"讀取結(jié)束"<<endl;
    closesocket(sockfd);
}
int  user() {
    char operation[10], name[20];        //操作與文件名
    char order[30] = "\0";                //輸入的命令
    char buff[80];                        //用來存儲(chǔ)經(jīng)過字符串格式化的order
    cout << "請(qǐng)輸入用戶名指令(user 用戶名):";
    strcpy(operation,"user");
    cin >> name;
    strcat(order, operation), strcat(order, " "), strcat(order, name);
    sprintf(buff, order);
    sendTCP(buff);                                    //發(fā)送指令
    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];                        //用來存儲(chǔ)經(jīng)過字符串格式化的order
    cout << "請(qǐng)輸入密碼指令(pass 密碼):" ;
    strcpy(operation,"pass");
    cin >> name;
    strcat(order, operation), strcat(order, " "), strcat(order, name);
    sprintf(buff, order);
    sendTCP(buff);                                    //發(fā)送指令
    recv(sockClient, rbuff, sizeof(rbuff), 0);        //接收信息
    cout << rbuff << endl;
    if (strcmp(rbuff, "wrong") == 0) {
        return 0;
    }
    return 1;
}
//***********************函數(shù)定義***********************

int command(){
    char operation[10], name[20];        //操作與文件名
    char order[30] = "\0";                //輸入的命令
    char buff[80];                        //用來存儲(chǔ)經(jīng)過字符串格式化的order
    FILE *fd1, *fd2;                    //File協(xié)議主要用于訪問本地計(jì)算機(jī)中的文件,fd指針指向要訪問的目標(biāo)文件
    int cnt;
    //發(fā)送連接請(qǐng)求成功,初始化數(shù)據(jù)
    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 << "請(qǐng)輸入要執(zhí)行的指令: ";
        cin >> operation;
//        cout<<"why:"<<operation<<endl;
        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;
        }


        //將指令整合進(jìn)order,并存放進(jìn)buff
        strcat(order, operation), strcat(order, " "), strcat(order, name);

        sprintf(buff, order);
        sendTCP(buff);                                    //發(fā)送指令
        recv(sockClient, rbuff, sizeof(rbuff), 0);        //接收信息
        cout << rbuff << endl;                            //pwd功能在這里已經(jīng)實(shí)現(xiàn)
        if (strncmp(rbuff, "get", 3) == 0) {            ///下載功能
            callServer(dataClient,dataAddr);
            fd1 = fopen(name, "wb");                    //用二進(jìn)制的方式打開文件,wb表示打開或新建一個(gè)二進(jìn)制文件(只允許寫數(shù)據(jù))
            if (fd1 == NULL) {
                cout << "打開或者新建 " << name << "文件失敗" << endl;
                return 1;
            }
            memset(rbuff, '\0', sizeof(rbuff));
            while ((cnt = recv(dataClient, rbuff, sizeof(rbuff), 0)) > 0) {
               // cout<<"緩沖區(qū)"<<rbuff<<endl<<"長度"<<cnt<<endl;
                fwrite(rbuff, sizeof(rbuff), 1, fd1);    //C 庫函數(shù) size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 把 ptr 所指向的數(shù)組中的數(shù)據(jù)寫入到給定流 stream 中。
            }
            closesocket(dataClient);
            fclose(fd1);                                //關(guān)閉文件
        }//get
        else if (strncmp(rbuff, "put", 3) == 0) { ///上傳功能
          //  cout<<"執(zhí)行"<<endl;
            strcpy(fileName, rbuff + 4);
            fd2 = fopen(fileName, "rb");                //打開一個(gè)二進(jìn)制文件,文件必須存在,只允許讀
            if (fd2) { //成功打開
               // cout<<"debug0"<<endl;
                if (!sendFile(dataClient, fd2)) {
                    cout << "發(fā)送失敗" << endl;
                    return 1;
                }
                fclose(fd2);
            } else {
                strcpy(sbuff, "無法打開文件\n");
                if (!send(sockClient, sbuff, sizeof(sbuff), 0)) {
                    return 1;
                }
            }

        }//put
        else if (strncmp(rbuff, "ls", 2) == 0) { ///ls功能
            list(dataClient);
        }//dir

        return 0;

}

int main() {
    while (1) {
        startSock();                //啟動(dòng)winsock并初始化
        if (callServer(sockClient,serverAddr) == -1) {    //發(fā)送連接請(qǐng)求失敗
            continue;
        }
        cout << "發(fā)送連接請(qǐng)求成功" << endl;

//        if (checkFlag == false) {//登陸
//            if (user() && pass()) {
//                checkFlag = true;
//            }
//            continue;
//        }
        checkFlag = true;

        if(checkFlag){
            help();
        }
        while(checkFlag){
            if(command()){
                break;
            }
        }
        cout<<"命令輸入結(jié)束"<<endl;
        closesocket(sockClient);    //關(guān)閉連接
        WSACleanup();                //釋放Winsock

        return 0;

    }
}
/*
192.168.0.100
user gyc
pass 123456
pwd
cd Debug
get 110.txt
*/

讀到這里,這篇“C++如何實(shí)現(xiàn)簡單FTP客戶端軟件開發(fā)”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI