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