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

本文为大家分享了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(); }

推荐阅读