返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++实现FTP综合应用详解
  • 328
分享到

C++实现FTP综合应用详解

C++FTP 2022-11-13 14:11:47 328人浏览 八月长安
摘要

本文为大家分享了FTP综合应用编程(c++),供大家参考,具体内容如下 1.学校实验 借鉴了网上一位大佬的作品,然后自己改改拿来完成了算是还行的作品。 代码一共大概是900多行,可以

本文为大家分享了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:%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
    RspnsPacket rspns = { OK,
            "欢迎进入FTP综合应用系统!\n"
            "你可以使用的命令:\n"
            "ls\t<展示当前目录下的文件(夹),无需参数>\n"
            "pwd\t<展示当前目录的绝对路径,无需参数>\n"
            "cd\t<切换到指定目录,参数为路径>\n"
            "down\t<下载文件,参数为文件名>\n"
            "up\t<上传文件,参数为文件名>\n"
            "quit\t<退出系统,无需参数>\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, "下载文件%s\n", 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   %-20s\n",
        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("绑定地址失败,错误代码:%d\n", 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] = '\0';
        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("%s\n", 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();
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: C++实现FTP综合应用详解

本文链接: https://lsjlt.com/news/171548.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C++实现FTP综合应用详解
    本文为大家分享了FTP综合应用编程(C++),供大家参考,具体内容如下 1.学校实验 借鉴了网上一位大佬的作品,然后自己改改拿来完成了算是还行的作品。 代码一共大概是900多行,可以...
    99+
    2022-11-13
    C++ FTP
  • 详解Redis在SpringBoot工程中的综合应用
    目录业务描述准备工作初始化数据添加项目依赖添加数据库访问配置业务逻辑代码设计及实现Domain对象设计Dao 逻辑对象设计Service 逻辑对象设计Controller逻辑对象设计...
    99+
    2024-04-02
  • 栈的应用-综合计数器的实现
    目录 前言 一、思路分析 二、代码实现 总结 前言 在实现综合计数器之前,大家应该先了解一下什么是前中后缀表达式 前缀、中缀和后缀表达式是表示数学表达式的三种不同方式。 前缀表达式(也称为波兰式或前缀记法):操作符位于操作数之前。例...
    99+
    2023-09-25
    java 数据结构
  • 深入浅出理解C语言指针的综合应用
    目录指针是什么?指针变量  使用指针变量的例子通过指针引用数组&数组名vs数组名野指针野指针成因1.指针未初始化2.指针越界访问如何避免野指针指针运算指针是什么? ...
    99+
    2024-04-02
  • Java用栈实现综合计算器
    目录栈Java实现栈栈实现综合计算器1.中缀表达式直接计算2.后缀表达式计算中缀表达式转后缀表达式栈 栈(stack)又名堆栈,它是一种运算受限的线性表 。限定仅在表尾进行插入和删除...
    99+
    2024-04-02
  • C语言指针综合应用的示例分析
    这篇文章将为大家详细讲解有关C语言指针综合应用的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。指针是什么?指针是c语言中的一个重要概念,也是C语言的一个重要的特色,正确而灵活地运用它,可以使程序简...
    99+
    2023-06-29
  • C#利用FluentFTP实现FTP上传下载功能详解
    目录FTP基础知识FTP环境搭建FluentFTP安装示例演示示例源码FTP作为日常工作学习中,非常重要的一个文件传输存储空间,想必大家都非常的熟悉了,那么如何快速的实现文件的上传下...
    99+
    2023-02-21
    C#实现FTP上传下载 C# FTP上传下载 C# FTP上传 C# FTP下载 C# FTP
  • Java Collection 接口和常用方法综合详解
    目录1. Collection 接口实现类的特点2. Collection 接口常用方法3. Collection接口遍历元素方式1- 使用Iterator(迭代器)4. Colle...
    99+
    2024-04-02
  • Java怎么用栈实现综合计算器
    本篇内容介绍了“Java怎么用栈实现综合计算器”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!栈栈(stack)又名堆栈,它是一种运算受限的线...
    99+
    2023-07-02
  • 浅谈java反射和自定义注解的综合应用实例
    前言前几天学习了反射和自定义注解,刚好工作中遇到一个小问题:前台传递到后台的必填字段为空,导致不能插入数据库。就是这样一个小问题,让我考虑到是否可以做一个通用的方法,让前台传递过来的必填字段在后台也校验一遍,如果传递为空,则把响应字段返回提...
    99+
    2023-05-31
    java 自定义注解 反射
  • Android应用隐私合规检测实现方案详解
    目录【前言】一、准备工作二、编写Xposed模块【前言】  为了响应国家对于个人隐私信息保护的号召,各应用渠道平台陆续出台了对应的检测手段去检测上架的应用是否存在隐私合规问...
    99+
    2024-04-02
  • 详解C/C++中低耦合代码的设计实现
    目录依赖倒置原则C/C++ 通过回调函数和信号槽的方式降低模块的耦合性在我们设计C/C++ 程序的时候,有时需要两个类或者两个模块相互“认识”,或者两个模块间...
    99+
    2023-01-30
    C++设计低耦合代码 C++低耦合代码 C++低耦合
  • C++abs函数实际应用详解
    目录abs函数是用来干什么的abs使用的头文件abs函数用法abs函数使用说明实战带入知识点实战导入算法分析 代码实现总结abs函数是用来干什么的 abs函数主要的作用是用...
    99+
    2022-11-13
    C++ abs函数 C++ abs函数用法
  • SpringBoot校园综合管理系统实现流程分步讲解
    目录一、前言介绍二、系统流程分析2.1数据增加流程2.2数据修改流程2.3数据删除流程三、系统详细设计3.1用户首页模块3.2跳蚤市场模块3.3带跑服务模块3.4校园周边模块四、管理...
    99+
    2024-04-02
  • 详解C/C++实现各种字符转换方法合集
    目录一、std::string 和 std::wstring 互转1、直接声明std::wstring2、wstring_convert3、WideCharToMultiByte和M...
    99+
    2024-04-02
  • 详解使用pymysql在python中对mysql的增删改查操作(综合)
    这一次将使用pymysql来进行一次对MySQL的增删改查的全部操作,相当于对前五次的总结: 先查阅数据库: 现在编写源码进行增删改查操作,源码为: #!/usr/bin/python #cod...
    99+
    2022-06-04
    中对 详解 操作
  • C#实现文件分割和合并的示例详解
    目录实践过程效果代码实践过程 效果 代码 public partial class frmSplit : Form { public frmSplit() { ...
    99+
    2022-12-26
    C#文件分割 合并 C#文件分割 C#文件合并
  • C和C++如何实现互相调用详解
    目录前言1、为什么会有差异?2、extern “C”3、C++调用C正确方式4、C调用C++补充:C/C++文件之间函数的引用总结前言 在项目开发过程中,我们...
    99+
    2023-01-10
    c++中调用c c和c++混合编译 c语言能调用c++吗
  • C/C++详解实现二层转发
    目录OSI第2层什么是MAC地址表二层转发C/C++代码实现总结OSI第2层 前两个字段分别是目的地址和源地址字段。第3个字段是2字节的类型字段,用来标识上一层是什么协议。 数据...
    99+
    2024-04-02
  • C#中逆变的实际应用场景详解
    目录前言协变的应用场景逆变的应用场景讨论总结前言 早期在学习泛型的协变与逆变时,网上的文章讲解、例子算是能看懂,但关于逆变的具体应用场景这方面的知识,我并没有深刻的认识。本文将在具体...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作