简单FTP客户端c++
Simple FTP Client C++
我试图在C/c++中创建一个简单的FTP客户端,这将做简单的操作(连接,检索文件)。我到目前为止所做的工作是连接和登录。我使用套接字连接到端口21,就像任何常规FTP客户端一样。我遇到的问题是连接到输入命令PASV时指定的端口。我获得消息,解析它,然后在输入PASV时从重播消息计算端口。
227 Entering Passive Mode (a1, a2, a3, a4, p1, p2)
DataPort = (p1 * 256) + p2
一旦我有了端口,我尝试创建另一个套接字并以同样的方式连接到它。这就是我的问题所在。到目前为止,我的代码张贴在下面。我不知道是否需要以同样的方式获得服务器地址。我没有从服务器得到响应(如果我实际上应该得到一个,我不知道)请提出任何问题或疑虑,谢谢。
const int FTP_PORT = 21; // Server Port
const int SIZE = 1024; // Size of Buffers
char receiveBuff[SIZE]; // Buffer to send to the server
char sendBuff[SIZE]; // Buffer to receive from server
char pasvBuff[] = "pasv"; // Buffer to see if PASV Command was entered
char quitBuff[] = "QUIT"; // Buffer to see if QUIT Command was entered
char pasvMessage[100]; // String for PASV information
int main(int argc, char *argv[])
{
int length = 0, i=0;
int a1, a2, a3, a4, p1, p2, dataPort; //PASV Information
/* Get Server Name from User */
if (argc != 2)
{
cerr << "Usage: " << argv[0] << " server" << endl;
return 1;
}
/* Obtain Host (Server) Info */
struct hostent *host;
host = gethostbyname(argv[1]);
if (host == (struct hostent *)NULL)
{
perror("Client: gethostbyname");
return 2;
}
/* Add Server Information */
struct sockaddr_in servAdr; // Internet address of server
memset(&servAdr, 0, sizeof(servAdr)); // Clear structure
servAdr.sin_family = AF_INET; // Set address typedef
memcpy(&servAdr.sin_addr, host->h_addr, host->h_length);
servAdr.sin_port = htons(FTP_PORT); // Use FTP port
/* Create Socket to Connect to FTP Server */
int origSock; // Original socket in client
if ((origSock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Client: generate error");
return 3;
}
/* Connect to FTP Server on Port 21 */
if (connect(origSock, (struct sockaddr *)&servAdr, sizeof(servAdr)) < 0)
{
perror("Client: connect error");
return 4;
}
/* Get Conenct Message and Print to Screen */
read(origSock, receiveBuff, sizeof(receiveBuff) - 1);
write(fileno(stdout), receiveBuff, sizeof(receiveBuff) - 1);
do
{
/* Clear Buffers */
memset(receiveBuff, 0, SIZE);
memset(sendBuff, 0, SIZE);
write(fileno(stdout), "Please enter a FTP Command: ", 28); // Write User Interface
read(fileno(stdin), sendBuff, SIZE); // Read Command from User
send(origSock, sendBuff, strlen(sendBuff) , 0); // Send Command to Server
read(origSock, receiveBuff, sizeof(receiveBuff) - 1); // Read Response from Server
write(fileno(stdout), receiveBuff, sizeof(receiveBuff) - 1); // Print Response from Server to screen
/* If PASV Command was Entered */
if (strncmp(sendBuff, pasvBuff, 4) == 0)
{
sscanf(receiveBuff, "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)", &a1,&a2,&a3,&a4,&p1,&p2);
dataPort = (p1 * 256) + p2;
struct sockaddr_in servAdr2; // Internet address of server
memset(&servAdr2, 0, sizeof(servAdr2)); // Clear structure
servAdr2.sin_family = AF_INET; // Set address typedef
memcpy(&servAdr2.sin_addr, host->h_addr, host->h_length);
servAdr.sin_port = htons(dataPort); // Use FTP port
/* Create Socket to Connect to FTP Server */
int dataSock; // Data socket in client
if ((dataSock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Client: generate error");
return 3;
}
/* Connect to FTP Server on Data Port */
if (connect(dataSock, (struct sockaddr *)&servAdr, sizeof(servAdr)) < 0)
{
perror("Client: connect error");
return 4;
}
read(dataSock, receiveBuff, sizeof(receiveBuff) - 1);
write(fileno(stdout), receiveBuff, sizeof(receiveBuff) - 1);
}
} while (strncmp(sendBuff, quitBuff, 4) != 0); // Go until QUIT Command is entered
close(origSock);
return 0;
}
当您解析PASV
回复时,您正在填充servAdr2
变量,但sin_port
字段除外。而是将报告的端口分配给servAdr.sin_port
字段。然后使用servAdr
而不是servAdr2
连接数据套接字。因此,您可以有效地将数据套接字连接到报告端口上服务器的原始IP地址,而不是连接到报告的IP地址(可以与服务器IP不同)。a1
- a4
是你要连接的IP地址的IPv4字节。
也就是说,如果服务器支持EPSV
命令,您确实应该使用它。它比PASV
更容易解析,因为PASV
没有标准化格式(因此要准备好解析多个特定于供应商的格式)。EPSV
通过以机器可解析的方式标准化格式解决了这个问题。
至于为什么你没有得到任何响应,这是因为你没有告诉服务器通过开放数据连接发送任何文件。发送PASV
仅仅打开服务器的数据端口。在连接到它之后,您必须在控制套接字上发送STOR
或RETR
命令,以便在数据套接字上实际执行文件传输。在传输完成后,您还必须在控制套接字上读取服务器的最终响应,然后才能发送任何新命令。
这是我写的一个c++套接字库,它有一个FTP客户端(连接,检索列表和文件)。代码中的注释解释了
https://github.com/pedro-vicente/lib_netsockets 基本上:
FTP使用两个TCP连接传输文件:一个控制连接和一个数据连接
在端口21上连接一个套接字(控制套接字)到FTP服务器
在套接字上收到来自FTP服务器的消息(代码:220)
使用USER命令发送登录到ftp服务器,并等待确认(331)
使用PASS命令发送密码并等待确认您已登录服务器(230)
接收文件:
使用被动模式:发送命令PASV
收到IP地址和端口227的应答,解析此消息
用给定的配置连接第二个套接字(数据套接字)
在控制套接字
上使用命令RETR通过数据套接字接收数据,关闭数据套接字
在控制套接字上使用QUIT命令退出会话
- "unknown ca"自生成的 CA、证书和客户端/服务器
- 如何将函数集合传递给客户端类,以便将它们当作客户端类本身的成员使用
- 使用调试/崩溃报告将应用程序部署到客户端
- 如何在本地机器上运行c++和javascript客户端代码(hackerbank风格)
- 如何通过套接字将文本文件的内容从服务器发送到客户端
- 从服务器传输到客户端的消息不会出现
- OpenSSL TLS服务器-使用客户端证书白名单
- 当服务中的事件被触发时,如何将响应从服务发送回客户端?
- 我可以与 python 服务器而不是 c++ 客户端建立 tcp/ip 套接字吗?
- 提升 Asio TCP 服务器 处理多个客户端
- boost::asio UDP 广播客户端仅接收"fast"数据包
- 如何绑定 C++ gRPC 客户端的网络接口
- C++套接字客户端到 Python 服务器未创建连接
- 用于解析 win64 堆栈跟踪的命令行客户端(可以访问符号服务器)
- 将相机数据从服务器实时流式传输到客户端
- 如何将 Firebase 与基于 Linux 的客户端应用配合使用,以便与服务器进行双向消息通信
- GRPC C++ TLS 客户端 grpc::SslCredentials() 方法不返回
- 计算出有多少客户端可以连接到我正在使用的一些tcp服务器代码
- 如何暂停插孔音频客户端
- 不将数据 socket.io c++(客户端)发送到 nodejs(服务器)socket.io