FTP 编写 4:命令解析
来源:互联网 发布:开展网络思想政治教育 编辑:程序博客网 时间:2024/06/14 14:05
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"; } }}
客户端重构
客户端也是将功能封装到一个类里面,但不需要多线程,运行函数如下:
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"; //创建Socket ser.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 ¶mter);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); //关闭 Winsock WSACleanup();}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"; //创建Socket ser.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"; //启动winSocket if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { std::cout << "Failed to load Winsock.\n"; return; } //创建Socket sListen = 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); //关闭 Winsock WSACleanup();}//多线程函数,创建的多线程运行此函数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 ¶mter); //文件接收函数 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 ¶mter){ 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
阅读全文
0 0
- FTP 编写 4:命令解析
- FTP命令解析
- 详细解析Linux scp和FTP命令
- 详细解析Linux scp和FTP命令 .
- Linux lftp命令和ftp命令用法解析与示例
- 编写简单的shell命令解析器
- 编写简单的shell命令解析器
- FTP协议命令+返回值+返回值解析
- 解析FTP的LIST命令发回的数据
- FTP协议命令+返回值+返回值解析
- ftp命令
- ftp命令
- ftp命令
- FTP命令
- ftp命令
- ftp命令
- FTP命令
- FTP命令
- RecyclerView在数据加载未完成时点击崩溃
- AIDL跨进程通信
- Git github使用
- How to Install the Latest GCC on Windows
- Thrift交流(二)thrift服务端和客户端实现 Nifty
- FTP 编写 4:命令解析
- 基于linux 3.10.49内核的pinctrl流程分析
- 阿里云部署Java web项目初体验
- ORACLE 05 基本查询
- Android ClassNotFoundException异常
- 数据结构——串的朴素模式和KMP匹配算法
- List数组对象 转到 String 数组当中
- ConvertUtils.register注册转换器
- leetcode 62. Unique Paths