FTP概述
文件传输协议(FTP)是网络共享文件的传输协议,广泛应用于网络应用软件。FTP的目标是提高文件共享性,可靠高效地传输数据。
传输文件时,FTP客户端程序首先与服务器建立连接,然后向服务器发送命令。服务器收到命令后响应并执行命令。FTP协议与操作系统无关。所有作业系统上的程式只要符合FTP通讯协定,就可以互相传输资料。本文主要以LINUX平台为基础,详细阐述FTP客户端的实现原理,并介绍如何用C语言编写简单的FTP客户端。
FTP协议
FTP协议比其他协议(如HTTP协议)复杂。与常规C/S应用程序不同,常规C/S应用程序通常只建立一个套接字连接,该连接同时处理服务器端和客户端连接命令以及数据传输。FTP协议通过与数据分离和发送命令的方法提高了效率。
FTP使用2个端口、1个数据端口和1个命令端口(也称为控制端口)。这两个端口通常为21(命令端口)和20(数据端口)。控制套接字用于传递命令,数据套接字用于传输数据。发送每个FTP命令后,FTP服务器将返回包含响应代码和说明信息的字符串。返回代码主要用于判断命令是否成功执行。
命令端口
通常,客户端有一个用于连接到FTP服务器的套接字,负责发送FTP命令和接收返回的响应信息。某些任务(如登录、目录更改、文件删除等)只需向此连接发送命令即可。
数据端口
对于有数据传输的操作,主要是显示目录列表,上传、下载文件,我们需要用不同的套接字完成。
如果使用被动模式,服务器端通常返回端口号。客户端必须打开另一个套接字才能连接到此端口。然后,可以根据任务发送命令。数据通过新打开的端口传输。
使用主动模式时,客户端通常向服务器端发送端口号,以便在此端口上侦听。服务器必须连接到客户端打开的此数据端口以传输数据。
下面简单介绍了FTP的主动模式和被动模式。
活动模式(PORT)
在主动模式下,客户端随机将大于1024的端口打开到服务器的命令端口P (21端口),开始连接,打开N 1端口侦听,向服务器发出“port N 1”命令,使服务器能够从自己的数据端口(20)主动连接到客户端指定的数据端口(N 1)。
FTP中的客户端只告诉服务器端口号,以便服务器能够连接到客户端指定的端口。客户端防火墙是从外部到内部的连接,可能会被阻止。
被动模式(PASV)
为了解决服务器与客户的连接问题,还有另一种FTP连接方法,即被动方法。命令连接和数据连接都是由客户端启动的,因此从服务器到客户端数据端口的连接由防火墙过滤的问题得到了解决。
在被动模式下,当FTP连接打开时,客户端将打开两个本地端口(N 1024和N 1)。
第一个端口连接到服务器的21个端口,并提交PASV命令。然后,服务器打开任意端口(P 1024)并返回到“227 entering passive mode (127,0,0,1,4,18)”。返回以227开头的信息。括号中是逗号分隔的6位数字,前4位是服务器的地址,后2位,倒数第二次乘256最后一位数字。这是FTP服务器为数据传输开放的端口。获得227 entering passive mode (h1、H2、H3、H4、P1、p2)后,端口号为p1*256 p2,IP地址为。也就是说,服务器上有打开的端口。客户端收到获取端口号的命令后,服务器的端口P通过N 1端口连接,并在两个端口之间传输数据。
常用FTP命令
FTP由每个命令的3至4个字符组成,命令后面有参数,用空格分隔。每个命令都以' rn '结尾。
要下载或上载文件,请先登录到FTP服务器,然后发送命令,最后退出。此过程中主要使用的命令有USER、PASS、SIZE、REST、CWD、RETR、PASV、PORT和QUIT。
指定USER:用户名。通常,这是连接控制后执行的第一个命令。用户gaoleyi r n:用户名为gaoleyi登录。
PASS:指定用户密码。此命令紧跟在USER命令之后。“PASS gaoleyirn”:密码为gaoleyi。
SIZE:返回服务器上指定文件的大小。SIZE rn:如果文件存在,则返回文件大小。
更改CWD:工作目录示例:“CWD dirnamern”。
PASV:允许服务器在数据端口上侦听并进入手动模式。示例:“PASVrn”。
PORT:通知FTP服务器客户端侦听的端口号,使FTP服务器能够以活动模式连接到客户端。示例:“端口h1、H2、H3、H4、P1、p2”。
下载RETR:文件。RETR rn:下载文件。
上传STOR:文件。STOR rn:上载文件。
REST:此命令不传输文件,而是跳过指定点之后的数据。此命令之后必须与要求文件传输的其他FTP命令一起使用。REST 100rn:将文件传输偏移重新指定为100字节。
QUIT:关闭与服务器的连接。
FTP响应代码
客户端发送FTP命令后,服务器返回响应代码。
响应代码以三位数字编码表示。
第一个数字提供了有关命令状态(如响应成功、失败或不完整)的一般说明。
第二个数字是响应类型的分类。例如,连接相关响应为2,用户身份认证为3。
第三个数字提供了更详细的信息。
第一个数字的含义如下:
1表示服务器已正确接收信息,尚未处理。
2表示服务器已正确处理信息。
3表示服务器正在正确接收和处理信息。
4表示信息暂时错误。
5表示永久的信息错误。
第二个数字的含义如下:
0表示语法。
1表示系统状态和信息。
2表示连接状态。
3表示与用户身份认证相关的信息。
4表示未定义。
5表示与文件系统相关的信息。
套接字编程的几个重要步骤
套接字客户端编程的主要步骤如下:
通过创建Socket () Socketconnect(),通过write()和read()连接到服务器来继续会话。结束close()套接字服务器端编程的主要步骤如下:
Socket()通过创建Socketbind()listen()侦听accept()接收连接的请求write()和read()会话close(),将套接字关闭到顶部
实现FTP客户端上传和下载功能。
例如,让我们详细了解一下FTP客户端。本文实现的FTP客户端具有以下功能:
客户端和FTP服务器建立套接字连接。向服务器发送USER、PASS命令,登录到FTP服务器。使用PASV命令获取服务器侦听的端口号并建立数据连接。使用RETR/STOR命令下载/上载文件。下载完成后,断开数据连接,发送QUIT命令退出。本例中使用的FTP服务器是filezilla。控制连接在整个交互过程中始终保持连接,每当传输文件时,数据连接首先打开,然后关闭。
客户端和FTP服务器建立套接字连接
客户端连接到服务器后,服务器将返回220的响应代码和一些欢迎消息。
图1。客户端连接到服务器端
清单1。客户端连接到FTP服务器,收到欢迎信息。
SOCKET control _ sock
Struct hostent * hp
Struct sockaddr _ in server
Memset (server,0,size of(struct sock addr _ in));
/*套接字初始化*/
Control _ sock=socket (af _ inet、sock _ stream、0);
HP=gethostbyname(server _ name);
Memcpy(、hp-h_addr、HP-h _ length);
=AF _ INET
=htons(端口);
/*连接到服务器端*/
Connect (control _ sock,(struct sockaddr *) server,size of(server));
/*客户端在服务器端收到欢迎信息。*/
Read (control _ sock、read _ buf和read _ len);
客户端登录到FTP服务器
客户端发送用户名和密码后,如果服务器身份认证通过,则返回230的响应代码。然后客户端可以向服务器端发送命令。
图2。客户端登录到FTP服务器
清单2。客户端发送用户名和密码,登录FTP服务器。
/*命令“user username r n”*/
sprint(send _ buf,' user% s r n ',username);
/*客户端向服务器端发送用户名*/
Write (control _ sock、send _ buf、str len(send _ buf));
/*客户端是“331 user name okay,need password”*/
Read (control _ sock、read _ buf和read _ len);
/*命令' passpassword r n' */
sprint(send _ buf,' pass% s r n ',password);
/*客户端向服务器端发送密码*/
Write (control _ sock、send _ buf、str len(send _ buf));
/*客户端接收服务器的响应代码和信息。通常为“230 user logged in,proceed。”*/
Read (control _ sock、read _ buf和read _ len);
客户端使FTP服务器处于手动模式
客户端下载/上载文件之前,必须先发送命令,使服务器处于手动模式。服务器打开和接收数据端口。返回响应代码227和数据连接的端口号。
图3。客户端将服务器置于手动模式
清单3。将服务器置于被动模式,从数据端口接收。
/*命令' pasv r n' */
sprint(send _ buf,' pasv r n ');
/*客户端指示服务器使用手动模式*/
Write (control _ sock、send _ buf、str len(send _ buf));
/*客户端接收服务器的响应代码和新打开的端口号。
*正常为“227 entering passive mode (h1、H2、H3、H4、P1、p2)”*/
Read (control _ sock、read _ buf和read _ len);
客户端以手动模式下载文件
客户端发送命令下载文件时。服务器返回响应代码150,并将文件内容发送到数据连接。
图4。客户端从FTP服务器端下载文件
清单4。客户端连接到FTP服务器的数据端口并下载文件。
/*将新打开的数据端口连接到服务器*/
Connect (data _ sock、(struct sockaddr *) server、size of(server));
/*命令“CWD dirname r n”*/
sprint(send _ buf,' CWD% s r n ',dirname);
/*客户端发送更改工作目录的命令*/
Write (control _ sock、send _ buf、str len(send _ buf));
/*客户端以“250 command okay”接收服务器的响应代码和信息。*/
Read (control _ sock、read _ buf和read _ len);
/*命令“size filename r n”*/
sprint(send _ buf,' size% s r n ',文件名);
/*客户端发送命令,从服务器端获取下载文件的大小。*/
Write (control _ sock、send _ buf、str len(send _ buf));
/*客户端接收服务器的响应代码和信息,通常为“213大小”*/
Read (control _ sock、read _ buf和read _ len);
/*命令“retr filename r n”*/
sprint(send _ buf,' retr% s r n ',文件名);
/*客户端发送命令从服务器端下载文件*/
Write (control _ sock、send _ buf、str len(send _ buf));
/*客户端将服务器的响应代码和信息接收到“150 opening data connection”。*/
Read (control _ sock、read _ buf和read _ len);
/*客户端生成文件*/
File _ handle=open (disk _ name、Cr flags、rwx all);
FOR(;{
.
/*客户端通过数据连接从服务器接收文件内容*/
Read (data _ sock、read _ buf、read _ len);
/*客户端写入文件*/
Write (file _ handle、read _ buf和read _ len);
.
}
/*客户端关闭文件*/
RC=close(file _ handle);
客户端关闭服务器
客户端下载完成后,发送命令关闭服务器并关闭连接。服务器返回响应代码200。
图5。从FTP服务器关闭客户端
清单5。客户端关闭数据连接,关闭FTP服务器,关闭控制连接
/*客户端关闭数据连接*/
关闭(data _ sock);
/*客户端将服务器的响应代码和信息接收到“226 transfer complete”。*/
Read (control _ sock、read _ buf和read _ len);
/*命令' quit r n' */
sprint(send _ buf,' quit r n ');
/*客户端断开与服务器端的连接*/
Write (control _ sock、send _ buf、str len(send _ buf));
/*客户端接收服务器的响应代码。通常为“200 closes connection”。*/
Read (control _ sock、read _ buf和read _ len);
/*客户端关闭控制连接*/
关闭(control _ sock);
此时文件下载已完成。发送FTP命令时,必须在命令后面加上“rn”。否则,服务器不会返回信息。回车回车“rn”是FTP命令的结束符号,服务器收到此符号后,客户端发送的命令将被认为已结束,开始处理。否则我会一直等下去。
现在,让我们看一下FTP服务器一端的反应。
清单6。客户端下载文件时FTP服务器的响应输出
(not logged in)) connected,sending welcome message.
(未登录)220-filezilla server版本0 . 9 . 36 beta
(not logged in)) 220 hello gaoleyi
(not logged in)) USER gaoleyi
(not logged in)331 password required for Gao leyi
(not loggedin)通路* * * * * * * * * *
Gaoleyi) 230 Logged on
高乐毅)PWD
Gao leyi)257 '/' is current directory。
高乐毅)大小
Gaoleyi) 213 4096
高乐毅)PASV
gaoleyi)227 entering passive mode(127,0,0,1,13,67)
Gaoleyi) RETR
Gaoleyi) 150连接接受
Gaoleyi) 226 Transfer OK
高乐毅)QUIT
高乐毅)221再见
首先,服务器准备就绪后返回220。客户端收到服务器端返回的响应代码后,依次发送“USER username”和“PASS password”命令登录。之后,服务器返回的响应代码以230开头,表示客户端已登录。此时,客户端通过发送PASV命令将服务器置于手动模式。如果服务器返回“227 entering passive mode (127,0,0,1,13,67)”等值,客户端将获取端口号并连接到服务器的数据端口。然后客户端发送下载命令,服务器返回响应代码150,并从数据端口发送数据。最后,服务器返回“226 transfer complete”,表示数据传输已完成。
但是,客户端不能一次发送多个命令。例如,要打开目录并显示此目录,必须发送CWD dirname、PASV、LIST。发送CWD dirname后,请等待响应代码,然后发送以下代码:PASV返回后,已打开另一个插座连接到相关端口。然后发送LIST,返回125,开始接收数据,最后返回226,表示完成。
传输多个文件时,请注意,每次新传输都必须再次使用PASV获取新端口号,收到数据后必须关闭数据连接,服务器才能返回2XX的成功响应。然后客户端可以继续传输下一个文件。
文件上载与文件下载相比,与登录验证和手动模式切换相同。只需更改发送到服务器端的命令,并通过数据连接发送文件内容即可。
客户端通过手动模式将文件上载到服务器
客户端发送上载文件的命令后,服务器将从数据连接接收文件。
图6。客户端连接到FTP服务器上的数据端口并上载文件
客户端通过活动模式将文件上载到服务器
到目前为止,本文介绍了客户端如何以手动模式上载和下载文件。下面介绍了客户端如何以主动模式下载文件。
图7。以活动模式从FTP服务器下载文件
清单7。使用活动模式从FTP服务器下载文件的C程序示例
.
SOCKET data _ sock
Data _ sock=插座(af _ inet、sock _ stream、0);
Struct sockaddr _ in name
Name.sin _ family=AF _ INET
Name。=htons(inad dr _ ANY);
Server _ port=p1 * 256 p2
长度=size of(name);
name . sin _ port=htons(server _ port);
Bind (server _ sock,(struct sockaddr *) name,length);
Struct sockaddr _ in client _ name
长度=size of(client _ name);
/*客户端连接埠p1*256 p2 */
Listen(server_sock,64);
/*命令“端口 r n”*/
短跑(send _ buf、' port1287、0、0、1、% d、% d r n '、P1、p2);
Write (control _ sock、send _ buf、str len(send _ buf));
/*客户端将服务器的响应代码和信息改为“200 port command successful”*/
Read (control _ sock、read _ buf和read _ len);
sprint(send _ buf,' retr r n ');
Write (control _ sock、send _ buf、str len(send _ buf));
/*客户端是“150 opening data channel for file transfer”*/
Read (control _ sock、read _ buf和read _ len);
/* FTP客户端接受服务器端连接请求*/
Data _ sock=accept (server _ sock,(struct sockaddr *) client _ name,length);
.
File _ handle=open (disk _ name、ro flags、rwx all);
FOR(;{
.
Read (data _ sock、read _ buf、read _ len);
Write (file _ handle、read _ buf和read _ len);
.
}
关闭(file _ handle);
客户端通过PORT命令指示服务器连接到自己的p1*256 p2端口。然后在此端口上侦听,等待FTP服务器连接,然后通过此数据端口传输文件。PORT方法在传输数据时,FTP客户端实际上等同于服务器端,FTP服务器主动连接自己。
断点续传
网络不稳定可能会导致文件传输过程中丢失连接。在这种情况下,客户端必须支持断点更新,然后可以从上次关闭的位置继续传输。必须使用REST命令。如果在断开连接之前,一个文件已经发送了512字节。断点更新以512开始,服务器跳过传输文件的前512个字节。
清单8。从FTP服务器断点继续下载文件
.
/*命令“rest offset r n”*/
sprint(send _ buf,' rest% LD r n ',offset);
/*指定客户端传输命令下载文件的偏移*/
Write (control _ sock、send _ buf、str len(send _ buf));
/*客户端接收服务器的响应代码和信息。
*通常为“350 restarting at position . send store or retrieve to initiate transfer”*/
Read (control _ sock、read _ buf和read _ len);
.
/*命令“retr filename r n”*/
sprint(send _ buf,' retr% s r n ',文件名);
/*客户机从服务器端下载文件,并发送命令跳过文件的上一个offset字节。*/
Write (control _ sock、send _ buf、str len(send _ buf));
/*客户端接收服务器的响应代码和信息。*
*正常情况是“150 connection accepted,restarting at offset position”*/
Read (control _ sock、read _ buf和read _ len);
.
File _ handle=open (disk _ name、Cr flags、rwx all);
/*指向文件写入的初始位置*/
Lseek (file _ handle、offset、seek _ set);
.
结束语
本文从应用程序实现的角度介绍了FTP协议。用详细的例子分析了FTP客户端如何使用主动模式和手动模式上传下载文件和更新断点。通过这篇文章,读者可以深入了解FTP客户端的原理。
来源:
1.《关于ftp客户端我想说使用 Socket 通信实现 FTP 客户端程序》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《关于ftp客户端我想说使用 Socket 通信实现 FTP 客户端程序》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/keji/1952127.html