首頁 > 軟體

C++實現FTP綜合應用詳解

2022-08-02 18:08:37

本文為大家分享了FTP綜合應用程式設計(C++),供大家參考,具體內容如下

1.學校實驗

借鑑了網上一位大佬的作品,然後自己改改拿來完成了算是還行的作品。

程式碼一共大概是900多行,可以直接貼上下來看看,其實還是很容易理解的。

執行的截圖附上:

使用者端:

伺服器端:

2.伺服器端程式碼

標頭檔案:(sizes.h)

#pragma once
 
//伺服器偵聽控制連線請求的埠
#define CMD_PORT 5858
//客戶機偵聽資料連線請求的埠
#define DATA_PORT 5850
//命令報文引數快取的大小
#define CMD_PARAM_SIZE 256
//回覆報文訊息快取的大小
#define RSPNS_TEXT_SIZE 256
#define BACKLOG 10
#define DATA_BUFSIZE 4096
 
//命令型別
typedef enum {
    LS, PWD, CD, DOWN, UP, QUIT
} CmdID;
 
//命令報文,從使用者端發往伺服器
typedef struct _CmdPacket {
    CmdID cmdid;
    char param[CMD_PARAM_SIZE];
} CmdPacket;
 
//回覆報文的型別
typedef enum {
    OK, ERR
} RspnsID;
 
//回覆報文,從伺服器發往使用者端
typedef struct _RspnsPacket {
    RspnsID rspnsid;
    char text[RSPNS_TEXT_SIZE];
} RspnsPacket;

原始檔:(伺服器端.cpp)

#include <WinSock2.h>
#include "sizes.h"
#include <iostream>
 
#pragma comment(lib, "ws2_32.lib")
 
//建立執行緒時傳遞的資料結構,內含控制連線通訊端和使用者端地址資訊:
struct threadData {
    SOCKET tcps;
    sockaddr_in clientaddr;
};
 
//全域性函數宣告:
//FTP初始化,建立一個偵聽通訊端:
int InitFTP(SOCKET *pListenSock);
int InitDataSocket(SOCKET *pDatatcps, SOCKADDR_IN *pClientAddr);
int ProcessCmd(SOCKET tcps, CmdPacket* pCmd, SOCKADDR_IN *pClientAddr);
int SendRspns(SOCKET tcps, RspnsPacket* prspns);
int RecvCmd(SOCKET tcps, char* pCmd);
int SendFileList(SOCKET datatcps);
int SendFileRecord(SOCKET datatcps, WIN32_FIND_DATA* pfd);
int SendFile(SOCKET datatcps, FILE* file);
int RecvFile(SOCKET datatcps, char* filename);
int FileExists(const char *filename);
 
//執行緒函數,引數包括相應控制連線的通訊端:
DWORD WINAPI ThreadFunc(LPVOID lpParam) {
    SOCKET tcps;
    sockaddr_in clientaddr;
    tcps = ((struct threadData *)lpParam)->tcps;
    clientaddr = ((struct threadData *)lpParam)->clientaddr;
    printf("socket的編號是:%u.n", tcps);
 
    //傳送回復報文給使用者端,內含命令使用說明:
    printf("Serve client %s:%dn", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
    RspnsPacket rspns = { OK,
            "歡迎進入FTP綜合應用系統!n"
            "你可以使用的命令:n"
            "lst<展示當前目錄下的檔案(夾),無需引數>n"
            "pwdt<展示當前目錄的絕對路徑,無需引數>n"
            "cdt<切換到指定目錄,引數為路徑>n"
            "downt<下載檔案,引數為檔名>n"
            "upt<上傳檔案,引數為檔名>n"
            "quitt<退出系統,無需引數>n"
    };
    SendRspns(tcps, &rspns);
 
    //迴圈獲取使用者端命令報文並進行處理
    for (;;) {
        CmdPacket cmd;
        if (!RecvCmd(tcps, (char *)&cmd))
            break;
        if (!ProcessCmd(tcps, &cmd, &clientaddr))
            break;
    }
 
    //執行緒結束前關閉控制連線通訊端:
    closesocket(tcps);
    delete lpParam;
    return 0;
}
 
int main(int argc, char* argv[]) {
    SOCKET tcps_listen;  //FTP伺服器控制連線偵聽通訊端
    struct threadData *pThInfo;
 
    if (!InitFTP(&tcps_listen))  //FTP初始化
        return 0;
    printf("FTP伺服器開始監聽,埠號為:%d。。。。。。n", CMD_PORT);
 
    //迴圈接受使用者端連線請求,並生成執行緒去處理:
    for (;;) {
        pThInfo = NULL;
        pThInfo = new threadData;
        if (pThInfo == NULL) {
            printf("為新執行緒申請空間失敗。n");
            continue;
        }
 
        int len = sizeof(struct threadData);
        //等待接受使用者端控制連線請求
        pThInfo->tcps = accept(tcps_listen, (SOCKADDR*)&pThInfo->clientaddr, &len);
 
        //建立一個執行緒來處理相應使用者端的請求:
        DWORD dwThreadId, dwThrdParam = 1;
        HANDLE hThread;
 
        hThread = CreateThread(
            NULL,               //無需安全性的繼承
            0,                    //預設執行緒棧大小
            ThreadFunc,            //執行緒入口函數
            pThInfo,            //執行緒入口函數的引數
            0,                    //立即啟動執行緒
            &dwThreadId);        //返回執行緒的id值
 
        //檢查返回值是否建立執行緒成功
        if (hThread == NULL) {
            printf("建立執行緒失敗。n");
            closesocket(pThInfo->tcps);
            delete pThInfo;
        }
    }
 
    return 0;
 
}
 
//FTP初始化,建立一個偵聽通訊端:
 
int InitFTP(SOCKET *pListenSock) {
    //按照此步驟建立新的伺服器端通訊端,嗯,沒錯,前三個都是這個步驟
    //startup->socket->bind->listen
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    SOCKET tcps_listen;
 
    wVersionRequested = MAKEWORD(2, 2);
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        printf("Winsock初始化時發生錯誤!n");
        return 0;
    }
    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
        WSACleanup();
        printf("無效Winsock版本!n");
        return 0;
    }
 
    tcps_listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (tcps_listen == INVALID_SOCKET) {
        WSACleanup();
        printf("建立Socket失敗!n");
        return 0;
    }
 
    SOCKADDR_IN tcpaddr;
    tcpaddr.sin_family = AF_INET;
    tcpaddr.sin_port = htons(CMD_PORT);
    tcpaddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    err = bind(tcps_listen, (SOCKADDR*)&tcpaddr, sizeof(tcpaddr));
    if (err != 0) {
        err = WSAGetLastError();
        WSACleanup();
        printf("Scoket繫結時發生錯誤!n");
        return 0;
    }
    err = listen(tcps_listen, 3);
    if (err != 0) {
        WSACleanup();
        printf("Scoket監聽時發生錯誤!n");
        return 0;
    }
 
    *pListenSock = tcps_listen;
    return 1;
}
 
 
//建立資料連線
//pDatatcps:用於儲存資料連線通訊端
//pClientAddr:指向使用者端的控制連線通訊端地址,需要使用其中的IP地址
//返回值:0表示失敗,1正常
int InitDataSocket(SOCKET *pDatatcps, SOCKADDR_IN *pClientAddr) {
    SOCKET datatcps;
 
    //建立socket
    datatcps = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (datatcps == INVALID_SOCKET) {
        printf("Creating data socket failed!n");
        return 0;
    }
 
    SOCKADDR_IN tcpaddr;
    memcpy(&tcpaddr, pClientAddr, sizeof(SOCKADDR_IN));
    tcpaddr.sin_port = htons(DATA_PORT);    //如若有什麼意外只需要在標頭檔案修改埠值
 
    //請求連線使用者端
    if (connect(datatcps, (SOCKADDR*)&tcpaddr, sizeof(tcpaddr)) == SOCKET_ERROR) {
        printf("Connecting to client failed!n");
        closesocket(datatcps);
        return 0;
    }
 
    *pDatatcps = datatcps;
    return 1;
}
 
//處理命令報文
//tcps:控制連線通訊端
//pcmd:指向待處理的命令報文
//pClientAddr:指向使用者端控制連線通訊端地址
//返回值:0表示有錯或者需要結束連線,1正常
 
int ProcessCmd(SOCKET tcps, CmdPacket* pCmd, SOCKADDR_IN *pClientAddr) {
    SOCKET datatcps;   //資料連線通訊端
    RspnsPacket rspns;  //回覆報文
    FILE* file;
 
    //根據命令型別分派執行:
    switch (pCmd->cmdid) {
    case LS://展示當前目錄下的檔案列表
        //首先建立資料連線:
        if (!InitDataSocket(&datatcps, pClientAddr))
            return 0;
        //傳送檔案列表資訊:
        if (!SendFileList(datatcps))
            return 0;
        break;
    case PWD://展示當前目錄的絕對路徑
        rspns.rspnsid = OK;
        //獲取當前目錄,並放至回覆報文中
        if (!GetCurrentDirectory(RSPNS_TEXT_SIZE, rspns.text))
            strcpy(rspns.text, "Can't get current dir!n");
        if (!SendRspns(tcps, &rspns))
            return 0;
        break;
    case CD://設定當前目錄,使用win32 API 介面函數
        if (SetCurrentDirectory(pCmd->param)) {
            rspns.rspnsid = OK;
            if (!GetCurrentDirectory(RSPNS_TEXT_SIZE, rspns.text))
                strcpy(rspns.text, "切換當前目錄成功!但是不能獲取到當前的檔案列表!n");
        }
        else {
            strcpy(rspns.text, "不能更換到所選目錄!n");
        }
        if (!SendRspns(tcps, &rspns))   //傳送回復報文
            return 0;
        break;
    case DOWN://處理下載檔案請求:
        file = fopen(pCmd->param, "rb");   //開啟要下載的檔案
        if (file) {
            rspns.rspnsid = OK;
            sprintf(rspns.text, "下載檔案%sn", pCmd->param);
            if (!SendRspns(tcps, &rspns)) {
                fclose(file);
                return 0;
            }
            else {
                //建立額外的資料連線來傳送資料:
                if (!InitDataSocket(&datatcps, pClientAddr)) {
                    fclose(file);
                    return 0;
                }
                if (!SendFile(datatcps, file))
                    return 0;
                fclose(file);
            }
        }
        else  //開啟檔案失敗
        {
            rspns.rspnsid = ERR;
            strcpy(rspns.text, "不能開啟檔案!n");
            if (!SendRspns(tcps, &rspns))
                return 0;
        }
        break;
    case UP://處理上傳檔案請求
        //首先傳送回復報文
        char filename[64];
        strcpy(filename, pCmd->param);
        //首先看一下伺服器上是否已經有這個檔案裡,如果有就告訴使用者端不用傳輸了
        if (FileExists(filename)) {
            rspns.rspnsid = ERR;
            sprintf(rspns.text, "伺服器已經存在名字為%s的檔案!n", filename);
            if (!SendRspns(tcps, &rspns))
                return 0;
        }
        else {
            rspns.rspnsid = OK;
            if (!SendRspns(tcps, &rspns))
                return 0;
            //另建立一個資料連線來接受資料:
            if (!InitDataSocket(&datatcps, pClientAddr))
                return 0;
            if (!RecvFile(datatcps, filename))
                return 0;
        }
        break;
    case QUIT:
        printf("使用者端斷開連線。n");
        rspns.rspnsid = OK;
        strcpy(rspns.text, "常來啊!n");
        SendRspns(tcps, &rspns);
        return 0;
 
 
    }
 
    return 1;
 
}
 
//傳送回復報文
int SendRspns(SOCKET tcps, RspnsPacket* prspns) {
    if (send(tcps, (char *)prspns, sizeof(RspnsPacket), 0) == SOCKET_ERROR) {
        printf("與使用者端失去連線。n");
        return 0;
    }
    return 1;
}
 
//接收命令報文
//tcps:控制連線通訊端
//pCmd:用於儲存返回的命令報文
//返回值:0表示有錯或者連線已經斷開,1表示正常
int RecvCmd(SOCKET tcps, char* pCmd) {                    //used to receive command from client
    int nRet;
    int left = sizeof(CmdPacket);
 
    //從控制連線中讀取資料,大小為 sizeof(CmdPacket):
    while (left) {
        nRet = recv(tcps, pCmd, left, 0);
        if (nRet == SOCKET_ERROR) {
            printf("從使用者端接受命令時發生未知錯誤!n");
            return 0;
        }
        if (!nRet) {
            printf("使用者端關閉了連線!n");
            return 0;
        }
 
        left -= nRet;
        pCmd += nRet;
    }
    return 1;   //成功獲取命令報文
}
 
 
//傳送一項檔案資訊:
int SendFileRecord(SOCKET datatcps, WIN32_FIND_DATA* pfd) {                    //used to send response to client
    char filerecord[MAX_PATH + 32];
    FILETIME ft;
    FileTimeToLocalFileTime(&pfd->ftLastWriteTime, &ft);
    SYSTEMTIME lastwtime;
    FileTimeToSystemTime(&ft, &lastwtime);
    char* dir = (char*)(pfd->dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY ? "<DIR>" : "");
    sprintf(filerecord, "%04d-%02d-%02d%02d:%02d   %5s   %10d   %-20sn",
        lastwtime.wYear,
        lastwtime.wMonth,
        lastwtime.wDay,
        lastwtime.wHour,
        lastwtime.wMinute,
        dir,
        pfd->nFileSizeLow,
        pfd->cFileName);
    if (send(datatcps, filerecord, strlen(filerecord), 0) == SOCKET_ERROR) {
        printf("傳送檔案列表時發生未知錯誤!n");
        return 0;
 
    }
    return 1;
}
 
 
//傳送檔案列表資訊
//datatcps:資料連線通訊端
//返回值:0表示出錯,1表示正常
int SendFileList(SOCKET datatcps) {
    HANDLE hff;
    WIN32_FIND_DATA fd;
 
    //搜尋檔案
    hff = FindFirstFile("*", &fd);
    if (hff == INVALID_HANDLE_VALUE)  //發生錯誤
    {
        const char* errstr = "不能列出檔案!n";
        printf("檔案列表輸出失敗!n");
        if (send(datatcps, errstr, strlen(errstr), 0) == SOCKET_ERROR) {
            printf("傳送給檔案列表時發生未知錯誤!n");
        }
        closesocket(datatcps);            return 0;
    }
 
    BOOL fMoreFiles = TRUE;
    while (fMoreFiles) {
        //傳送此項檔案資訊:
        if (!SendFileRecord(datatcps, &fd)) {
            closesocket(datatcps);
            return 0;
        }
        //搜尋下一個檔案
        fMoreFiles = FindNextFile(hff, &fd);
    }
    closesocket(datatcps);
    return 1;
}
 
//通過資料連線傳送檔案
int SendFile(SOCKET datatcps, FILE* file) {
    char buf[1024];
    printf("傳送檔案資料中。。。。。。");
    for (;;) {                //從檔案中迴圈讀取資料並行送使用者端
        int r = fread(buf, 1, 1024, file);
        if (send(datatcps, buf, r, 0) == SOCKET_ERROR) {
            printf("與使用者端失去連線!n");
            closesocket(datatcps);
            return 0;
        }
        if (r < 1024)   //檔案傳輸結束
        {
            break;
        }
    }
    closesocket(datatcps);
    printf("完成傳輸!n");
    return 1;
}
 
//接收檔案
//datatcps:資料連線通訊端,通過它來接收資料
//filename:用於存放資料的檔名
int RecvFile(SOCKET datatcps, char* filename) {
    char buf[1024];
    FILE* file = fopen(filename, "wb");
    if (!file) {
        printf("寫入檔案時發生未知錯誤!n");
        fclose(file);
        closesocket(datatcps);
        return 0;
    }
    printf("接受檔案資料中。。。。。。");
    while (1) {
        int r = recv(datatcps, buf, 1024, 0);
        if (r == SOCKET_ERROR) {
            printf("從使用者端接受檔案時發生未知錯誤!n");
            fclose(file);
            closesocket(datatcps);
            return 0;
        }
        if (!r) {
            break;
        }
        fwrite(buf, 1, r, file);
    }
    fclose(file);
    closesocket(datatcps);
    printf("完成傳輸!n");
    return 1;
}
 
//檢測檔案是否存在:
int FileExists(const char *filename)
{
    WIN32_FIND_DATA fd;
    if (FindFirstFile(filename, &fd) == INVALID_HANDLE_VALUE)
        return 0;
    return 1;
}

3.使用者端

標頭檔案:(sizes.h)

#pragma once
 
//伺服器偵聽控制連線請求的埠
#define CMD_PORT 5858
//客戶機偵聽資料連線請求的埠
#define DATA_PORT 5850
//命令報文引數快取的大小
#define CMD_PARAM_SIZE 256
//回覆報文訊息快取的大小
#define RSPNS_TEXT_SIZE 256
#define BACKLOG 10
#define DATA_BUFSIZE 4096
 
//命令型別
typedef enum {
    LS, PWD, CD, DOWN, UP, QUIT
} CmdID;
 
//命令報文,從使用者端發往伺服器
typedef struct _CmdPacket {
    CmdID cmdid;
    char param[CMD_PARAM_SIZE];
} CmdPacket;
 
//回覆報文的型別
typedef enum {
    OK, ERR
} RspnsID;
 
//回覆報文,從伺服器發往使用者端
typedef struct _RspnsPacket {
    RspnsID rspnsid;
    char text[RSPNS_TEXT_SIZE];
} RspnsPacket;

原始檔:(使用者端.cpp)

#include <WinSock2.h>
#include <windows.h>
#include "sizes.h"
#include <tchar.h>
#include <iostream>
 
#pragma comment(lib, "ws2_32.lib")
 
//讀取回復報文
void do_read_rspns(SOCKET fd, RspnsPacket *ptr)
{
    int count = 0;
    int size = sizeof(RspnsPacket);
    while (count < size)
    {
        int nRead = recv(fd, (char *)ptr + count, size - count, 0);
        if (nRead <= 0)
        {
            printf("讀取伺服器的回覆失敗!n");
            closesocket(fd);
            exit(1);
        }
        count += nRead;
    }
}
 
//傳送命令報文
void do_write_cmd(SOCKET fd, CmdPacket *ptr)
{
    int size = sizeof(CmdPacket);
    int flag = send(fd, (char *)ptr, size, 0);
    if (flag == SOCKET_ERROR)
    {
        printf("給伺服器傳送命令失敗!n");
        closesocket(fd);
        WSACleanup();
        exit(1);
    }
}
 
//建立資料連線通訊端並進入偵聽狀態
SOCKET create_data_socket()
{
    SOCKET sockfd;
    struct sockaddr_in my_addr;
    //建立用於資料連線的通訊端
    if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
    {
        printf("建立用於資料連線的通訊端失敗!n");
        WSACleanup();
        exit(1);
    }
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(DATA_PORT);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    memset(&(my_addr.sin_zero), 0, sizeof(my_addr.sin_zero));
 
    //繫結
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == SOCKET_ERROR)
    {
        int err = WSAGetLastError();
        printf("繫結地址失敗,錯誤程式碼:%dn", err);
        closesocket(sockfd);
        WSACleanup();
        exit(1);
    }
 
    //偵聽資料連線請求
    if (listen(sockfd, 1) == SOCKET_ERROR)
    {
        printf("監聽資料連線失敗!n");
        closesocket(sockfd);
        WSACleanup();
        exit(1);
    }
    return sockfd;
}
 
//處理list命令
void list(SOCKET sockfd)
{
    int sin_size;
    int nRead;
    CmdPacket cmd_packet;
    SOCKET newsockfd, data_sockfd;
    struct sockaddr_in their_add;
    char data_buf[DATA_BUFSIZE];
 
    //建立資料連線
    newsockfd = create_data_socket();
    //構建命令報文並行送至伺服器
    cmd_packet.cmdid = LS;//沒有引數
    do_write_cmd(sockfd, &cmd_packet);
    sin_size = sizeof(struct sockaddr_in);
    //接受伺服器的資料連線請求
    if ((data_sockfd = accept(newsockfd, (struct sockaddr*)&their_add, &sin_size)) == INVALID_SOCKET)
    {
        printf("獲取檔案列表失敗!n");
        closesocket(newsockfd);
        closesocket(sockfd);
        WSACleanup();
        exit(1);
    }
 
    //每次讀到多少資料就顯示多少,直到資料連線斷開
    while (true)
    {
        nRead = recv(data_sockfd, data_buf, DATA_BUFSIZE - 1, 0);
        if (nRead == SOCKET_ERROR)
        {
            printf("讀取伺服器回覆失敗!n");
            closesocket(data_sockfd);
            closesocket(newsockfd);
            closesocket(sockfd);
            WSACleanup();
            exit(1);
        }
 
        if (nRead == 0)//資料讀取結束
            break;
 
        //顯示資料
        data_buf[nRead] = '';
        printf("%s", data_buf);
 
    }
    closesocket(data_sockfd);
    closesocket(newsockfd);
}
//處理pwd命令:
void pwd(int sockfd)
{
    CmdPacket cmd_packet;
    RspnsPacket rspns_packet;
 
    cmd_packet.cmdid = PWD;
    //傳送命令報文並讀取回復:
    do_write_cmd(sockfd, &cmd_packet);
    do_read_rspns(sockfd, &rspns_packet);
    printf("%sn", rspns_packet.text);
}
 
//處理cd命令:
void cd(int sockfd)
{
    CmdPacket cmd_packet;
    RspnsPacket rspns_packet;
 
 
    cmd_packet.cmdid = CD;
    scanf("%s", cmd_packet.param);
 
    //傳送命令報文並讀取回復:
    do_write_cmd(sockfd, &cmd_packet);
    do_read_rspns(sockfd, &rspns_packet);
    if (rspns_packet.rspnsid == ERR)
        printf("%s", rspns_packet.text);
}
 
 
//處理down命令,即下載檔案:
void get_file(SOCKET sockfd)
{
    FILE *fd;
    char data_buf[DATA_BUFSIZE];
 
    CmdPacket cmd_packet;
    RspnsPacket rspns_packet;
 
    SOCKET newsockfd, data_sockfd;
    struct sockaddr_in their_addr;
    int sin_size;
    int count;
 
    //設定命令報文:
    cmd_packet.cmdid = DOWN;
    scanf("%s", cmd_packet.param);
 
    //開啟或者建立本地檔案以供寫資料:
    fd = fopen(cmd_packet.param, "wb");//使用二進位制方程
    if (fd == NULL)
    {
        printf("開啟檔案%s來寫入失敗!n", cmd_packet.param);
        return;
    }
 
    //建立資料連線並偵聽伺服器的連線請求:
    newsockfd = create_data_socket();
 
    //傳送報文請求:
    do_write_cmd(sockfd, &cmd_packet);
 
    //讀取回復報文:
    do_read_rspns(sockfd, &rspns_packet);
    if (rspns_packet.rspnsid == ERR)
    {
        printf("%s", rspns_packet.text);
        closesocket(newsockfd);
 
        fclose(fd);
        //刪除檔案:
        DeleteFile(cmd_packet.param);
        return;
    }
 
    sin_size = sizeof(struct sockaddr_in);
    //等待接受伺服器的連線請求
    if ((data_sockfd = accept(newsockfd, (struct sockaddr *)&their_addr, &sin_size)) == INVALID_SOCKET)
    {
        printf("獲取檔案失敗!n");
        closesocket(newsockfd);
 
        fclose(fd);
        //刪除檔案:
        DeleteFile(cmd_packet.param);
        return;
    }
 
    //迴圈讀取網路資料並寫入檔案:
    while ((count = recv(data_sockfd, data_buf, DATA_BUFSIZE, 0)) > 0)
        fwrite(data_buf, sizeof(char), count, fd);
 
    closesocket(data_sockfd);
    closesocket(newsockfd);
    fclose(fd);
}
 
//處理put命令,即上傳檔案
void put_file(SOCKET sockfd)
{
    FILE *fd;
    CmdPacket cmd_packet;
    RspnsPacket rspns_packet;
    char data_buf[DATA_BUFSIZE];
 
    SOCKET newsockfd, data_sockfd;
    struct sockaddr_in their_addr;
    int sin_size;
    int count;
    cmd_packet.cmdid = UP;
    scanf("%s", cmd_packet.param);
 
    //開啟本地檔案用於讀取資料
    fd = fopen(cmd_packet.param, "rb");
    if (fd == NULL)
    {
        printf("開啟檔案%s來讀取資料失敗!n", cmd_packet.param);
        return;
    }
 
    //建立資料連線通訊端並進入偵聽狀態;
    newsockfd = create_data_socket();
 
    //傳送命令報文
    do_write_cmd(sockfd, &cmd_packet);
 
    //讀取回復報文
    do_read_rspns(sockfd, &rspns_packet);
    if (rspns_packet.rspnsid == ERR)
    {
        printf("%s", rspns_packet.text);
        closesocket(newsockfd);
        fclose(fd);
        return;
    }
 
    sin_size = sizeof(struct sockaddr_in);
    //準備接受資料連線
    if ((data_sockfd = accept(newsockfd, (struct sockaddr *)&their_addr, &sin_size)) == INVALID_SOCKET)
    {
        printf("上傳檔案傳輸錯誤!n");
        closesocket(newsockfd);
        fclose(fd);
        return;
    }
    //迴圈從檔案中讀取資料並行給伺服器
    while (true)
    {
        count = fread(data_buf, sizeof(char), DATA_BUFSIZE, fd);
        send(data_sockfd, data_buf, count, 0);
        if (count < DATA_BUFSIZE)//資料已經讀完或者發生cuowu
            break;
    }
 
    closesocket(data_sockfd);
    closesocket(newsockfd);
    fclose(fd);
}
 
//處理退出命令
void quit(int sockfd)
{
    CmdPacket cmd_packet;
    RspnsPacket rspns_packet;
 
    cmd_packet.cmdid = QUIT;
    do_write_cmd(sockfd, &cmd_packet);
    do_read_rspns(sockfd, &rspns_packet);
    printf("%s", rspns_packet.text);
    getchar();
}
 
void main()
{
    SOCKET sockfd;
    struct sockaddr_in their_addr;
    char cmd[10];
    RspnsPacket rspns_packet;
 
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    wVersionRequested = MAKEWORD(2, 2);
    //Winsock初始化
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0)
    {
        printf("WinSock初始化失敗!n");
        return;
    }
 
    //確認WindSock DLL的版本是2.2
    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
    {
        printf("WindSock版本不是2.2!n");
        WSACleanup();
        return;
    }
 
    //建立用於控制諒解的socket
    sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sockfd == INVALID_SOCKET)
    {
        printf("建立通訊端失敗!n");
        WSACleanup();
        exit(1);
    }
    their_addr.sin_family = AF_INET;
    their_addr.sin_port = htons(CMD_PORT);
    their_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    memset(&(their_addr.sin_zero), 0, sizeof(their_addr.sin_zero));
 
    //連線伺服器
    if (connect(sockfd, (struct sockaddr*)&their_addr, sizeof(struct sockaddr)) == SOCKET_ERROR)
    {
        printf("連線伺服器失敗!n");
        closesocket(sockfd);
        WSACleanup();
        exit(1);
    }
 
    //連線成功後,首先接受伺服器發回的訊息
    do_read_rspns(sockfd, &rspns_packet);
    printf("%s", rspns_packet.text);
 
    //主迴圈:讀取使用者輸入並分配執行
    while (true)
    {
        scanf("%s", cmd);
        switch (cmd[0])
        {
        case 'l'://處理List命令
            list(sockfd);
            break;
        case 'p'://處理pwd命令
            pwd(sockfd);
            break;
        case 'c'://處理cd命令
            cd(sockfd);
            break;
        case 'd'://處理down命令
            get_file(sockfd);
            break;
        case 'u'://處理up命令
            put_file(sockfd);
            break;
        case 'q'://處理quit命令
            quit(sockfd);
            break;
        default:
            printf("不存在的命令!n");
            break;
        }
        if (cmd[0] == 'q')
            break;
    }
    WSACleanup();
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com