C++實現(xiàn)FTP綜合應(yīng)用詳解
本文為大家分享了FTP綜合應(yīng)用編程(C++),供大家參考,具體內(nèi)容如下
1.學(xué)校實驗
借鑒了網(wǎng)上一位大佬的作品,然后自己改改拿來完成了算是還行的作品。
代碼一共大概是900多行,可以直接粘貼下來看看,其實還是很容易理解的。
運(yùn)行的截圖附上:
客戶端:
服務(wù)器端:
2.服務(wù)器端代碼
頭文件:(sizes.h)
#pragma once ? //服務(wù)器偵聽控制連接請求的端口 #define CMD_PORT 5858 //客戶機(jī)偵聽數(shù)據(jù)連接請求的端口 #define DATA_PORT 5850 //命令報文參數(shù)緩存的大小 #define CMD_PARAM_SIZE 256 //回復(fù)報文消息緩存的大小 #define RSPNS_TEXT_SIZE 256 #define BACKLOG 10 #define DATA_BUFSIZE 4096 ? //命令類型 typedef enum { ?? ?LS, PWD, CD, DOWN, UP, QUIT } CmdID; ? //命令報文,從客戶端發(fā)往服務(wù)器 typedef struct _CmdPacket { ?? ?CmdID cmdid; ?? ?char param[CMD_PARAM_SIZE]; } CmdPacket; ? //回復(fù)報文的類型 typedef enum { ?? ?OK, ERR } RspnsID; ? //回復(fù)報文,從服務(wù)器發(fā)往客戶端 typedef struct _RspnsPacket { ?? ?RspnsID rspnsid; ?? ?char text[RSPNS_TEXT_SIZE]; } RspnsPacket;
源文件:(服務(wù)器端.cpp)
#include <WinSock2.h> #include "sizes.h" #include <iostream> ? #pragma comment(lib, "ws2_32.lib") ? //創(chuàng)建線程時傳遞的數(shù)據(jù)結(jié)構(gòu),內(nèi)含控制連接套接字和客戶端地址信息: struct threadData { ?? ?SOCKET tcps; ?? ?sockaddr_in clientaddr; }; ? //全局函數(shù)聲明: //FTP初始化,創(chuàng)建一個偵聽套接字: 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); ? //線程函數(shù),參數(shù)包括相應(yīng)控制連接的套接字: 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); ? ?? ?//發(fā)送回復(fù)報文給客戶端,內(nèi)含命令使用說明: ?? ?printf("Serve client %s:%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port)); ?? ?RspnsPacket rspns = { OK, ?? ??? ??? ?"歡迎進(jìn)入FTP綜合應(yīng)用系統(tǒng)!\n" ?? ??? ??? ?"你可以使用的命令:\n" ?? ??? ??? ?"ls\t<展示當(dāng)前目錄下的文件(夾),無需參數(shù)>\n" ?? ??? ??? ?"pwd\t<展示當(dāng)前目錄的絕對路徑,無需參數(shù)>\n" ?? ??? ??? ?"cd\t<切換到指定目錄,參數(shù)為路徑>\n" ?? ??? ??? ?"down\t<下載文件,參數(shù)為文件名>\n" ?? ??? ??? ?"up\t<上傳文件,參數(shù)為文件名>\n" ?? ??? ??? ?"quit\t<退出系統(tǒng),無需參數(shù)>\n" ?? ?}; ?? ?SendRspns(tcps, &rspns); ? ?? ?//循環(huán)獲取客戶端命令報文并進(jìn)行處理 ?? ?for (;;) { ?? ??? ?CmdPacket cmd; ?? ??? ?if (!RecvCmd(tcps, (char *)&cmd)) ?? ??? ??? ?break; ?? ??? ?if (!ProcessCmd(tcps, &cmd, &clientaddr)) ?? ??? ??? ?break; ?? ?} ? ?? ?//線程結(jié)束前關(guān)閉控制連接套接字: ?? ?closesocket(tcps); ?? ?delete lpParam; ?? ?return 0; } ? int main(int argc, char* argv[]) { ?? ?SOCKET tcps_listen; ?//FTP服務(wù)器控制連接偵聽套接字 ?? ?struct threadData *pThInfo; ? ?? ?if (!InitFTP(&tcps_listen)) ?//FTP初始化 ?? ??? ?return 0; ?? ?printf("FTP服務(wù)器開始監(jiān)聽,端口號為:%d。。。。。。\n", CMD_PORT); ? ?? ?//循環(huán)接受客戶端連接請求,并生成線程去處理: ?? ?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); ? ?? ??? ?//創(chuàng)建一個線程來處理相應(yīng)客戶端的請求: ?? ??? ?DWORD dwThreadId, dwThrdParam = 1; ?? ??? ?HANDLE hThread; ? ?? ??? ?hThread = CreateThread( ?? ??? ??? ?NULL, ? ? ? ? ? ? ? //無需安全性的繼承 ?? ??? ??? ?0,?? ??? ??? ??? ??? ?//默認(rèn)線程棧大小 ?? ??? ??? ?ThreadFunc,?? ??? ??? ?//線程入口函數(shù) ?? ??? ??? ?pThInfo,?? ??? ??? ?//線程入口函數(shù)的參數(shù) ?? ??? ??? ?0,?? ??? ??? ??? ??? ?//立即啟動線程 ?? ??? ??? ?&dwThreadId);?? ??? ?//返回線程的id值 ? ?? ??? ?//檢查返回值是否創(chuàng)建線程成功 ?? ??? ?if (hThread == NULL) { ?? ??? ??? ?printf("創(chuàng)建線程失敗。\n"); ?? ??? ??? ?closesocket(pThInfo->tcps); ?? ??? ??? ?delete pThInfo; ?? ??? ?} ?? ?} ? ?? ?return 0; ? } ? //FTP初始化,創(chuàng)建一個偵聽套接字: ? int InitFTP(SOCKET *pListenSock) { ?? ?//按照此步驟創(chuàng)建新的服務(wù)器端套接字,嗯,沒錯,前三個都是這個步驟 ?? ?//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初始化時發(fā)生錯誤!\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("創(chuàng)建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綁定時發(fā)生錯誤!\n"); ?? ??? ?return 0; ?? ?} ?? ?err = listen(tcps_listen, 3); ?? ?if (err != 0) { ?? ??? ?WSACleanup(); ?? ??? ?printf("Scoket監(jiān)聽時發(fā)生錯誤!\n"); ?? ??? ?return 0; ?? ?} ? ?? ?*pListenSock = tcps_listen; ?? ?return 1; } ? ? //建立數(shù)據(jù)連接 //pDatatcps:用于存儲數(shù)據(jù)連接套接字 //pClientAddr:指向客戶端的控制連接套接字地址,需要使用其中的IP地址 //返回值:0表示失敗,1正常 int InitDataSocket(SOCKET *pDatatcps, SOCKADDR_IN *pClientAddr) { ?? ?SOCKET datatcps; ? ?? ?//創(chuàng)建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表示有錯或者需要結(jié)束連接,1正常 ? int ProcessCmd(SOCKET tcps, CmdPacket* pCmd, SOCKADDR_IN *pClientAddr) { ?? ?SOCKET datatcps; ? //數(shù)據(jù)連接套接字 ?? ?RspnsPacket rspns; ?//回復(fù)報文 ?? ?FILE* file; ? ?? ?//根據(jù)命令類型分派執(zhí)行: ?? ?switch (pCmd->cmdid) { ?? ?case LS://展示當(dāng)前目錄下的文件列表 ?? ??? ?//首先建立數(shù)據(jù)連接: ?? ??? ?if (!InitDataSocket(&datatcps, pClientAddr)) ?? ??? ??? ?return 0; ?? ??? ?//發(fā)送文件列表信息: ?? ??? ?if (!SendFileList(datatcps)) ?? ??? ??? ?return 0; ?? ??? ?break; ?? ?case PWD://展示當(dāng)前目錄的絕對路徑 ?? ??? ?rspns.rspnsid = OK; ?? ??? ?//獲取當(dāng)前目錄,并放至回復(fù)報文中 ?? ??? ?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://設(shè)置當(dāng)前目錄,使用win32 API 接口函數(shù) ?? ??? ?if (SetCurrentDirectory(pCmd->param)) { ?? ??? ??? ?rspns.rspnsid = OK; ?? ??? ??? ?if (!GetCurrentDirectory(RSPNS_TEXT_SIZE, rspns.text)) ?? ??? ??? ??? ?strcpy(rspns.text, "切換當(dāng)前目錄成功!但是不能獲取到當(dāng)前的文件列表!\n"); ?? ??? ?} ?? ??? ?else { ?? ??? ??? ?strcpy(rspns.text, "不能更換到所選目錄!\n"); ?? ??? ?} ?? ??? ?if (!SendRspns(tcps, &rspns)) ? //發(fā)送回復(fù)報文 ?? ??? ??? ?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 { ?? ??? ??? ??? ?//創(chuàng)建額外的數(shù)據(jù)連接來傳送數(shù)據(jù): ?? ??? ??? ??? ?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://處理上傳文件請求 ?? ??? ?//首先發(fā)送回復(fù)報文 ?? ??? ?char filename[64]; ?? ??? ?strcpy(filename, pCmd->param); ?? ??? ?//首先看一下服務(wù)器上是否已經(jīng)有這個文件里,如果有就告訴客戶端不用傳輸了 ?? ??? ?if (FileExists(filename)) { ?? ??? ??? ?rspns.rspnsid = ERR; ?? ??? ??? ?sprintf(rspns.text, "服務(wù)器已經(jīng)存在名字為%s的文件!\n", filename); ?? ??? ??? ?if (!SendRspns(tcps, &rspns)) ?? ??? ??? ??? ?return 0; ?? ??? ?} ?? ??? ?else { ?? ??? ??? ?rspns.rspnsid = OK; ?? ??? ??? ?if (!SendRspns(tcps, &rspns)) ?? ??? ??? ??? ?return 0; ?? ??? ??? ?//另建立一個數(shù)據(jù)連接來接受數(shù)據(jù): ?? ??? ??? ?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; ? } ? //發(fā)送回復(fù)報文 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表示有錯或者連接已經(jīng)斷開,1表示正常 int RecvCmd(SOCKET tcps, char* pCmd) {?? ??? ??? ??? ??? ?//used to receive command from client ?? ?int nRet; ?? ?int left = sizeof(CmdPacket); ? ?? ?//從控制連接中讀取數(shù)據(jù),大小為 sizeof(CmdPacket): ?? ?while (left) { ?? ??? ?nRet = recv(tcps, pCmd, left, 0); ?? ??? ?if (nRet == SOCKET_ERROR) { ?? ??? ??? ?printf("從客戶端接受命令時發(fā)生未知錯誤!\n"); ?? ??? ??? ?return 0; ?? ??? ?} ?? ??? ?if (!nRet) { ?? ??? ??? ?printf("客戶端關(guān)閉了連接!\n"); ?? ??? ??? ?return 0; ?? ??? ?} ? ?? ??? ?left -= nRet; ?? ??? ?pCmd += nRet; ?? ?} ?? ?return 1; ? //成功獲取命令報文 } ? ? //發(fā)送一項文件信息: 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("發(fā)送文件列表時發(fā)生未知錯誤!\n"); ?? ??? ?return 0; ? ?? ?} ?? ?return 1; } ? ? //發(fā)送文件列表信息 //datatcps:數(shù)據(jù)連接套接字 //返回值:0表示出錯,1表示正常 int SendFileList(SOCKET datatcps) { ?? ?HANDLE hff; ?? ?WIN32_FIND_DATA fd; ? ?? ?//搜索文件 ?? ?hff = FindFirstFile("*", &fd); ?? ?if (hff == INVALID_HANDLE_VALUE) ?//發(fā)生錯誤 ?? ?{ ?? ??? ?const char* errstr = "不能列出文件!\n"; ?? ??? ?printf("文件列表輸出失??!\n"); ?? ??? ?if (send(datatcps, errstr, strlen(errstr), 0) == SOCKET_ERROR) { ?? ??? ??? ?printf("發(fā)送給文件列表時發(fā)生未知錯誤!\n"); ?? ??? ?} ?? ??? ?closesocket(datatcps);?? ??? ??? ?return 0; ?? ?} ? ?? ?BOOL fMoreFiles = TRUE; ?? ?while (fMoreFiles) { ?? ??? ?//發(fā)送此項文件信息: ?? ??? ?if (!SendFileRecord(datatcps, &fd)) { ?? ??? ??? ?closesocket(datatcps); ?? ??? ??? ?return 0; ?? ??? ?} ?? ??? ?//搜索下一個文件 ?? ??? ?fMoreFiles = FindNextFile(hff, &fd); ?? ?} ?? ?closesocket(datatcps); ?? ?return 1; } ? //通過數(shù)據(jù)連接發(fā)送文件 int SendFile(SOCKET datatcps, FILE* file) { ?? ?char buf[1024]; ?? ?printf("發(fā)送文件數(shù)據(jù)中。。。。。。"); ?? ?for (;;) {?? ??? ??? ??? ?//從文件中循環(huán)讀取數(shù)據(jù)并發(fā)送客戶端 ?? ??? ?int r = fread(buf, 1, 1024, file); ?? ??? ?if (send(datatcps, buf, r, 0) == SOCKET_ERROR) { ?? ??? ??? ?printf("與客戶端失去連接!\n"); ?? ??? ??? ?closesocket(datatcps); ?? ??? ??? ?return 0; ?? ??? ?} ?? ??? ?if (r < 1024) ? //文件傳輸結(jié)束 ?? ??? ?{ ?? ??? ??? ?break; ?? ??? ?} ?? ?} ?? ?closesocket(datatcps); ?? ?printf("完成傳輸!\n"); ?? ?return 1; } ? //接收文件 //datatcps:數(shù)據(jù)連接套接字,通過它來接收數(shù)據(jù) //filename:用于存放數(shù)據(jù)的文件名 int RecvFile(SOCKET datatcps, char* filename) { ?? ?char buf[1024]; ?? ?FILE* file = fopen(filename, "wb"); ?? ?if (!file) { ?? ??? ?printf("寫入文件時發(fā)生未知錯誤!\n"); ?? ??? ?fclose(file); ?? ??? ?closesocket(datatcps); ?? ??? ?return 0; ?? ?} ?? ?printf("接受文件數(shù)據(jù)中。。。。。。"); ?? ?while (1) { ?? ??? ?int r = recv(datatcps, buf, 1024, 0); ?? ??? ?if (r == SOCKET_ERROR) { ?? ??? ??? ?printf("從客戶端接受文件時發(fā)生未知錯誤!\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 ? //服務(wù)器偵聽控制連接請求的端口 #define CMD_PORT 5858 //客戶機(jī)偵聽數(shù)據(jù)連接請求的端口 #define DATA_PORT 5850 //命令報文參數(shù)緩存的大小 #define CMD_PARAM_SIZE 256 //回復(fù)報文消息緩存的大小 #define RSPNS_TEXT_SIZE 256 #define BACKLOG 10 #define DATA_BUFSIZE 4096 ? //命令類型 typedef enum { ?? ?LS, PWD, CD, DOWN, UP, QUIT } CmdID; ? //命令報文,從客戶端發(fā)往服務(wù)器 typedef struct _CmdPacket { ?? ?CmdID cmdid; ?? ?char param[CMD_PARAM_SIZE]; } CmdPacket; ? //回復(fù)報文的類型 typedef enum { ?? ?OK, ERR } RspnsID; ? //回復(fù)報文,從服務(wù)器發(fā)往客戶端 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") ? //讀取回復(fù)報文 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("讀取服務(wù)器的回復(fù)失敗!\n"); ?? ??? ??? ?closesocket(fd); ?? ??? ??? ?exit(1); ?? ??? ?} ?? ??? ?count += nRead; ?? ?} } ? //發(fā)送命令報文 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("給服務(wù)器發(fā)送命令失??!\n"); ?? ??? ?closesocket(fd); ?? ??? ?WSACleanup(); ?? ??? ?exit(1); ?? ?} } ? //創(chuàng)建數(shù)據(jù)連接套接字并進(jìn)入偵聽狀態(tài) SOCKET create_data_socket() { ?? ?SOCKET sockfd; ?? ?struct sockaddr_in my_addr; ?? ?//創(chuàng)建用于數(shù)據(jù)連接的套接字 ?? ?if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) ?? ?{ ?? ??? ?printf("創(chuàng)建用于數(shù)據(jù)連接的套接字失敗!\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); ?? ?} ? ?? ?//偵聽數(shù)據(jù)連接請求 ?? ?if (listen(sockfd, 1) == SOCKET_ERROR) ?? ?{ ?? ??? ?printf("監(jiān)聽數(shù)據(jù)連接失??!\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]; ? ?? ?//創(chuàng)建數(shù)據(jù)連接 ?? ?newsockfd = create_data_socket(); ?? ?//構(gòu)建命令報文并發(fā)送至服務(wù)器 ?? ?cmd_packet.cmdid = LS;//沒有參數(shù) ?? ?do_write_cmd(sockfd, &cmd_packet); ?? ?sin_size = sizeof(struct sockaddr_in); ?? ?//接受服務(wù)器的數(shù)據(jù)連接請求 ?? ?if ((data_sockfd = accept(newsockfd, (struct sockaddr*)&their_add, &sin_size)) == INVALID_SOCKET) ?? ?{ ?? ??? ?printf("獲取文件列表失??!\n"); ?? ??? ?closesocket(newsockfd); ?? ??? ?closesocket(sockfd); ?? ??? ?WSACleanup(); ?? ??? ?exit(1); ?? ?} ? ?? ?//每次讀到多少數(shù)據(jù)就顯示多少,直到數(shù)據(jù)連接斷開 ?? ?while (true) ?? ?{ ?? ??? ?nRead = recv(data_sockfd, data_buf, DATA_BUFSIZE - 1, 0); ?? ??? ?if (nRead == SOCKET_ERROR) ?? ??? ?{ ?? ??? ??? ?printf("讀取服務(wù)器回復(fù)失?。n"); ?? ??? ??? ?closesocket(data_sockfd); ?? ??? ??? ?closesocket(newsockfd); ?? ??? ??? ?closesocket(sockfd); ?? ??? ??? ?WSACleanup(); ?? ??? ??? ?exit(1); ?? ??? ?} ? ?? ??? ?if (nRead == 0)//數(shù)據(jù)讀取結(jié)束 ?? ??? ??? ?break; ? ?? ??? ?//顯示數(shù)據(jù) ?? ??? ?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; ?? ?//發(fā)送命令報文并讀取回復(fù): ?? ?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); ? ?? ?//發(fā)送命令報文并讀取回復(fù): ?? ?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; ? ?? ?//設(shè)置命令報文: ?? ?cmd_packet.cmdid = DOWN; ?? ?scanf("%s", cmd_packet.param); ? ?? ?//打開或者創(chuàng)建本地文件以供寫數(shù)據(jù): ?? ?fd = fopen(cmd_packet.param, "wb");//使用二進(jìn)制方程 ?? ?if (fd == NULL) ?? ?{ ?? ??? ?printf("打開文件%s來寫入失敗!\n", cmd_packet.param); ?? ??? ?return; ?? ?} ? ?? ?//創(chuàng)建數(shù)據(jù)連接并偵聽服務(wù)器的連接請求: ?? ?newsockfd = create_data_socket(); ? ?? ?//發(fā)送報文請求: ?? ?do_write_cmd(sockfd, &cmd_packet); ? ?? ?//讀取回復(fù)報文: ?? ?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); ?? ?//等待接受服務(wù)器的連接請求 ?? ?if ((data_sockfd = accept(newsockfd, (struct sockaddr *)&their_addr, &sin_size)) == INVALID_SOCKET) ?? ?{ ?? ??? ?printf("獲取文件失敗!\n"); ?? ??? ?closesocket(newsockfd); ? ?? ??? ?fclose(fd); ?? ??? ?//刪除文件: ?? ??? ?DeleteFile(cmd_packet.param); ?? ??? ?return; ?? ?} ? ?? ?//循環(huán)讀取網(wǎng)絡(luò)數(shù)據(jù)并寫入文件: ?? ?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); ? ?? ?//打開本地文件用于讀取數(shù)據(jù) ?? ?fd = fopen(cmd_packet.param, "rb"); ?? ?if (fd == NULL) ?? ?{ ?? ??? ?printf("打開文件%s來讀取數(shù)據(jù)失?。n", cmd_packet.param); ?? ??? ?return; ?? ?} ? ?? ?//創(chuàng)建數(shù)據(jù)連接套接字并進(jìn)入偵聽狀態(tài); ?? ?newsockfd = create_data_socket(); ? ?? ?//發(fā)送命令報文 ?? ?do_write_cmd(sockfd, &cmd_packet); ? ?? ?//讀取回復(fù)報文 ?? ?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); ?? ?//準(zhǔn)備接受數(shù)據(jù)連接 ?? ?if ((data_sockfd = accept(newsockfd, (struct sockaddr *)&their_addr, &sin_size)) == INVALID_SOCKET) ?? ?{ ?? ??? ?printf("上傳文件傳輸錯誤!\n"); ?? ??? ?closesocket(newsockfd); ?? ??? ?fclose(fd); ?? ??? ?return; ?? ?} ?? ?//循環(huán)從文件中讀取數(shù)據(jù)并發(fā)給服務(wù)器 ?? ?while (true) ?? ?{ ?? ??? ?count = fread(data_buf, sizeof(char), DATA_BUFSIZE, fd); ?? ??? ?send(data_sockfd, data_buf, count, 0); ?? ??? ?if (count < DATA_BUFSIZE)//數(shù)據(jù)已經(jīng)讀完或者發(fā)生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; ?? ?} ? ?? ?//確認(rèn)WindSock DLL的版本是2.2 ?? ?if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) ?? ?{ ?? ??? ?printf("WindSock版本不是2.2!\n"); ?? ??? ?WSACleanup(); ?? ??? ?return; ?? ?} ? ?? ?//創(chuàng)建用于控制諒解的socket ?? ?sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ?? ?if (sockfd == INVALID_SOCKET) ?? ?{ ?? ??? ?printf("創(chuàng)建套接字失敗!\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)); ? ?? ?//連接服務(wù)器 ?? ?if (connect(sockfd, (struct sockaddr*)&their_addr, sizeof(struct sockaddr)) == SOCKET_ERROR) ?? ?{ ?? ??? ?printf("連接服務(wù)器失敗!\n"); ?? ??? ?closesocket(sockfd); ?? ??? ?WSACleanup(); ?? ??? ?exit(1); ?? ?} ? ?? ?//連接成功后,首先接受服務(wù)器發(fā)回的消息 ?? ?do_read_rspns(sockfd, &rspns_packet); ?? ?printf("%s", rspns_packet.text); ? ?? ?//主循環(huán):讀取用戶輸入并分配執(zhí)行 ?? ?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(); }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
基于C++11的threadpool線程池(簡潔且可以帶任意多的參數(shù))
C++11 加入了線程庫,從此告別了標(biāo)準(zhǔn)庫不支持并發(fā)的歷史。然而 c++ 對于多線程的支持還是比較低級,稍微高級一點(diǎn)的用法都需要自己去實現(xiàn),譬如線程池、信號量等2019-04-04C++實現(xiàn)LeetCode(203.移除鏈表元素)
這篇文章主要介紹了C++實現(xiàn)LeetCode(203.移除鏈表元素),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08vscode C++開發(fā)環(huán)境配置步驟詳解(教你如何用vscode編寫寫C++)
這篇文章主要介紹了vscode C++開發(fā)環(huán)境配置詳細(xì)教程(教你如何用vscode編寫寫C++),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03淺析string 與char* char[]之間的轉(zhuǎn)換
與char*不同的是,string不一定以NULL('\0')結(jié)束。string長度可以根據(jù)length()得到,string可以根據(jù)下標(biāo)訪問。所以,不能將string直接賦值給char*2013-10-10C語言中結(jié)構(gòu)體struct編寫的一些要點(diǎn)解析
這篇文章主要介紹了C語言中結(jié)構(gòu)體struct編寫的一些要點(diǎn)解析,談到了結(jié)構(gòu)體的聲明和指針指向等重要知識點(diǎn),需要的朋友可以參考下2016-04-04