ftp傳輸文件命令,FTP 編寫 4:命令解析

 2023-10-12 阅读 14 评论 0

摘要:FTP 編寫 4:命令解析 ????我們知道在現實生活中使用的 FTP 是應答式的,客戶端和服務端按照一定的規定進行交流,不是隨便弄的,在上幾篇中的 FTP 沒有人機交互的功能。所以這篇文章的主要內容是按照平時 FTP 的交流規則重構一下整個工程的代碼ÿ

FTP 編寫 4:命令解析


????我們知道在現實生活中使用的 FTP 是應答式的,客戶端和服務端按照一定的規定進行交流,不是隨便弄的,在上幾篇中的 FTP 沒有人機交互的功能。所以這篇文章的主要內容是按照平時 FTP 的交流規則重構一下整個工程的代碼,并加入命令解析功能。

命令解析

????這部分命令解析只是簡單模擬一下 FTP 的,在 FTP 的規則中還有應答返回值的規定,現在把它省略,簡單定義一下服務端和客戶端的交流規則

????現在的交流過程是這樣的:在服務端和客戶端啟動以后,客戶端向服務端發起連接,然后服務端向客戶端發送一條歡迎信息;然后等待客戶端發送相應的指令,根據指令進行答復和操作

//命令解析函數:將受到的命令進行分解,用字符分割函數分成指令和參數兩部分
int Client::commandParse(char * instruck, std::string & paramter)
{std::string string(buf);std::cout << string;std::vector<std::string> command;//以空格為分隔符進行分割Tool::splitString(string, command, std::string(" "));//判斷傳入的參數個數是否正確if (command.size() != 2) {paramter = "";return -1;}//返回相應指令對應的數值if (command[0] == "STOR") {paramter = command[1];return 1;}if (command[0] == "RETR") {paramter = command[1];return 2;}//默認返回錯誤指令return 0;
}//字符分割函數
void Tool::splitString(const std::string & input, std::vector<std::string>& output, std::string &delim)
{std::string::size_type pos1, pos2;pos1 = 0;pos2 = input.find(delim);while (std::string::npos != pos2){output.push_back(input.substr(pos1, pos2 - pos1));pos1 = pos2 + delim.size();pos2 = input.find(delim, pos1);}if (pos1 != input.length())output.push_back(input.substr(pos1));
}

服務端重構

????服務端的重構主要是將服務端運行的部分抽離出來寫成一個類,類中包含了服務端的所有功能函數,并且在多線程中運行,服務端中的運行函數如下:

void Server::running()
{//與客戶端進行連接以后就發送一個歡迎信息welcome();//然后進入無限循環,等待客戶端的命令進行下一步操作while (true) {if (recv(server, buf, maxLen, 0) == 0) {std::cout << "recv() Faied!\n";}std::string paramter;int cmd = commandParse(buf, paramter);switch (cmd) {case 0:std::cout << "Command is invalid\n";break;case 1:std::cout << "Start receive the file from client.\n";receiveFile(paramter);break;case 2:std::cout << "Start send file to client.\n";sendFile(paramter);break;default:std::cout << "Command is invalid\n";}}
}

客戶端重構

ftp傳輸文件命令、????客戶端也是將功能封裝到一個類里面,但不需要多線程,運行函數如下:

void Client::running()
{memset(buf, 0, sizeof(buf));if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {std::cout << "Failed to load Winsock\n";system("pause");return;}//char addr[20] = "113.54.167.16";char addr[20] = "192.168.1.119";//創建Socketser.sin_family = AF_INET;ser.sin_port = htons(iPort);inet_pton(AF_INET, addr, (void*)&ser.sin_addr.s_addr);client = socket(AF_INET, SOCK_STREAM, 0);if (client == INVALID_SOCKET) {std::cout << "socket() Failed\n";system("pause");return;}//連接并進行簡單的操作if (connect(client, (struct sockaddr*)&ser, sizeof(ser)) == INVALID_SOCKET) {std::cout << "connect() Failed\n";system("pause");return;}else {//接收服務端發送的數據iLen = recv(client, buf, sizeof(buf), 0);if (iLen == 0) {system("pause");return;}else if (iLen == SOCKET_ERROR) {std::cout << "recv() Failed\n";system("pause");return;}std::cout << "recv() data from server:" << buf << std::endl;}while (true) {//輸入相應的數據發送給服務端std::cout << ">>";std::cin.getline(buf, 1024);std::string paramter;int cmd = commandParse(buf, paramter);switch (cmd) {case 0:std::cout << "Command is invalid\n";break;case 1:std::cout << "Start receive the file from client.\n";downloadFile(paramter);break;case 2:std::cout << "Start send file to client.\n";uploadFile(paramter);break;default:std::cout << "Command is invalid\n";}}
}

源代碼

客戶端

//main.cpp
#pragma comment(lib,"ws2_32.lib")#include "Client.h"void main()
{Client client;client.running();system("pause");
}//Client.h
#pragma once
#include <WinSock2.h>
#include <string>class Client
{
public:Client();~Client();void running();bool uploadFile(std::string file);bool downloadFile(std::string file);int commandParse(char* instruck, std::string &paramter);private:SOCKET client;char buf[1024];//定義相應的數據WSADATA wsaData;int iPort = 5050;//對應的服務端的端口int iLen, iSend;struct sockaddr_in ser;};//Client.cpp
#include "Client.h"
#include "Tool.h"#include <iostream>
#include <WS2tcpip.h>Client::Client()
{
}Client::~Client()
{//關閉連接并退出closesocket(client);//關閉 WinsockWSACleanup();
}void Client::running()
{memset(buf, 0, sizeof(buf));if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {std::cout << "Failed to load Winsock\n";system("pause");return;}//char addr[20] = "113.54.167.16";char addr[20] = "192.168.1.119";//創建Socketser.sin_family = AF_INET;ser.sin_port = htons(iPort);inet_pton(AF_INET, addr, (void*)&ser.sin_addr.s_addr);client = socket(AF_INET, SOCK_STREAM, 0);if (client == INVALID_SOCKET) {std::cout << "socket() Failed\n";system("pause");return;}//連接并進行簡單的操作if (connect(client, (struct sockaddr*)&ser, sizeof(ser)) == INVALID_SOCKET) {std::cout << "connect() Failed\n";system("pause");return;}else {//接收服務端發送的數據iLen = recv(client, buf, sizeof(buf), 0);if (iLen == 0) {system("pause");return;}else if (iLen == SOCKET_ERROR) {std::cout << "recv() Failed\n";system("pause");return;}std::cout << "recv() data from server:" << buf << std::endl;}while (true) {//輸入相應的數據發送給服務端std::cout << ">>";std::cin.getline(buf, 1024);std::string paramter;int cmd = commandParse(buf, paramter);switch (cmd) {case 0:std::cout << "Command is invalid\n";break;case 1:std::cout << "Start receive the file from client.\n";downloadFile(paramter);break;case 2:std::cout << "Start send file to client.\n";uploadFile(paramter);break;default:std::cout << "Command is invalid\n";}}
}bool Client::uploadFile(std::string file)
{return false;
}bool Client::downloadFile(std::string file)
{return false;
}int Client::commandParse(char * instruck, std::string & paramter)
{std::string string(buf);std::cout << string;std::vector<std::string> command;Tool::splitString(string, command, std::string(" "));if (command.size() != 2) {paramter = "";return -1;}if (command[0] == "STOR") {paramter = command[1];return 1;}if (command[0] == "RETR") {paramter = command[1];return 2;}return 0;
}

服務端

//main.cpp
#include <Winsock2.h>
#include <Ws2tcpip.h>
#include <iostream>
#include <thread>
#include <vector>
#pragma comment(lib,"ws2_32.lib")#include "Server.h"//多線程函數,創建的多線程運行此函數
void server(SOCKET s);void main()
{//定義相關的數據int iPort = 5050;//定義其端口WSADATA wsaData;//Winsock 的啟動參數SOCKET sListen, sAccept;//套接口關鍵字,分別用于監聽和接收連接int iLen;int iSend;char buf[] = "I am a server";struct sockaddr_in ser, cli;//網絡地址//定義多線程指針,用于創建線程std::thread* t;//用于線程的管理,保存創建的多線程指針,程序結束時釋放占用的內存std::vector<std::thread*> tManage;Server* server = NULL;std::cout << "----------------------------\n";std::cout << "Server waitting\n";std::cout << "----------------------------\n";//啟動winSocketif (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {std::cout << "Failed to load Winsock.\n";return;}//創建SocketsListen = socket(AF_INET, SOCK_STREAM, 0);if (sListen == INVALID_SOCKET) {std::cout << "socket() Failed:" << WSAGetLastError() <<"\n";return;}//綁定IP地址ser.sin_family = AF_INET;ser.sin_port = htons(iPort);ser.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(sListen, (LPSOCKADDR)&ser, sizeof(ser)) == SOCKET_ERROR) {std::cout << "bind() Failed\n";return;}//監聽if (listen(sListen, 5) == SOCKET_ERROR) {std::cout << "listen() Failed\n";return;}iLen = sizeof(cli);//獲取客戶端網絡地址的長度//接受連接和發送歡迎信息//用循環使程序一直運行while (true) {//接收連接sAccept = accept(sListen, (struct sockaddr*)&cli, &iLen);if (sAccept == INVALID_SOCKET) {std::cout << "accept() Failed\n";break;}//創建新的線程,并加入容器中,并將線程后臺運行//t = new std::thread(server, sAccept);//tManage.push_back(t);//t->detach();server = new Server(sAccept);t = new std::thread(&Server::running, server);tManage.push_back(t);t->detach();}//釋放指針占用的內存for (int i = 0; i < tManage.size(); i++) {delete(tManage[i]);}//關閉監聽closesocket(sListen);//關閉 WinsockWSACleanup();
}//多線程函數,創建的多線程運行此函數
void server(SOCKET s) {SOCKET socket = s;struct sockaddr_in ser, cli;//網絡地址int iSend, iRecv;char buf[1024] = "I am a server";//顯示客戶端的 IP 信息char clibuf[20] = { '\0' };inet_ntop(AF_INET, (void*)&cli.sin_addr, clibuf, 16);std::cout << "Accept client IP:" << clibuf << ":" << ntohs(cli.sin_port) << std::endl;//發送信息給客戶端iSend = send(socket, buf, sizeof(buf), 0);if (iSend == SOCKET_ERROR) {std::cout << "send() Failed\n";}else if (iSend == 0) {std::cout << "send() Zero\n";}else {std::cout << "Send byte:" << iSend << std::endl;std::cout << "----------------------------------\n";}//使用循環不斷接受客戶端發送來的信息并顯示while (true) {iRecv = recv(socket, buf, sizeof(buf), 0);if (iRecv == 0) {//std::cout << "recv() Zero\n";}else if (iRecv == SOCKET_ERROR) {std::cout << "recv() Failed\n";}else {std::cout << "recv() data from server:" << buf << std::endl;}}
}//Server.h
#pragma once#include <Winsock2.h>
#include <string>class Server
{
public:Server(SOCKET s);~Server();//歡迎函數bool welcome();//服務端運行函數void running();//命令解析函數int commandParse(char* instruck, std::string &paramter);//文件接收函數bool receiveFile(std::string filename);//文件發送bool sendFile(std::string filename);private:SOCKET server;int maxLen;char buf[1024];
};//Server.cpp
#include "Server.h"
#include "Tool.h"#include <iostream>
#include <vector>Server::Server(SOCKET s):server(s)
{maxLen = 1024;
}Server::~Server()
{
}bool Server::welcome()
{char welcome[1024] = "Welcome, my friend\n";//發送信息給客戶端int iSend = send(server, welcome, sizeof(welcome), 0);if (iSend == SOCKET_ERROR) {std::cout << "send() Failed\n";return false;}return true;
}void Server::running()
{welcome();while (true) {if (recv(server, buf, maxLen, 0) == 0) {std::cout << "recv() Faied!\n";}std::string paramter;int cmd = commandParse(buf, paramter);switch (cmd) {case 0:std::cout << "Command is invalid\n";break;case 1:std::cout << "Start receive the file from client.\n";receiveFile(paramter);break;case 2:std::cout << "Start send file to client.\n";sendFile(paramter);break;default:std::cout << "Command is invalid\n";}}
}int Server::commandParse(char* instruck, std::string &paramter)
{std::string string(buf);std::cout << string;std::vector<std::string> command;Tool::splitString(string, command, std::string(" "));//std::cout << command[0] << " " << command[1] << std::endl;if (command.size() != 2) {paramter = "";return -1;}if (command[0] == "STOR") {paramter = command[1];return 1;}if (command[0] == "RETR") {paramter = command[1];return 2;}return -1;
}bool Server::receiveFile(std::string filename)
{return false;
}bool Server::sendFile(std::string filename)
{return false;
}

工具類(字符分割方法,服務端與客戶端完全一樣)

//Tool.h
#pragma once
#include <string>
#include <vector>class Tool
{
public:Tool();~Tool();//字符串分割函數static void splitString(const std::string &input, std::vector<std::string> &output, std::string &delim);
};//Tool.cpp
#include "Tool.h"#include <sstream>
#include <istream>Tool::Tool()
{
}Tool::~Tool()
{
}void Tool::splitString(const std::string & input, std::vector<std::string>& output, std::string &delim)
{std::string::size_type pos1, pos2;pos1 = 0;pos2 = input.find(delim);while (std::string::npos != pos2){output.push_back(input.substr(pos1, pos2 - pos1));pos1 = pos2 + delim.size();pos2 = input.find(delim, pos1);}if (pos1 != input.length())output.push_back(input.substr(pos1));
}

源代碼地址

https://github.com/lw1243925457/FTP

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/2/135615.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息