linux下FTP编程socket.docx
- 文档编号:12129710
- 上传时间:2023-04-17
- 格式:DOCX
- 页数:14
- 大小:139KB
linux下FTP编程socket.docx
《linux下FTP编程socket.docx》由会员分享,可在线阅读,更多相关《linux下FTP编程socket.docx(14页珍藏版)》请在冰豆网上搜索。
linux下FTP编程socket
使用Socket通信实现FTP客户端程序
FTP客户端如FlashFXP,FileZilla被广泛应用,原理上都是用底层的Socket来实现。
FTP客户端与服务器端进行数据交换必须建立两个套接字,一个作为命令通道,一个作为数据通道。
前者用于客户端向服务器发送命令,如登录,删除某个文件,后者用于接收数据,例如下载或上传文件等。
本文详细阐述如何调用系统接口发送FTP命令实现文件上传下载等FTP客户端功能,让读者对FTP客户端的原理有一个深入的了解。
FTP概述
oFTP协议
o实现FTP客户端上传下载功能
o结束语
o参考资料
o评论
FTP概述
文件传输协议(FTP)作为网络共享文件的传输协议,在网络应用软件中具有广泛的应用。
FTP的目标是提高文件的共享性和可靠高效地传送数据。
在传输文件时,FTP客户端程序先与服务器建立连接,然后向服务器发送命令。
服务器收到命令后给予响应,并执行命令。
FTP协议与操作系统无关,任何操作系统上的程序只要符合FTP协议,就可以相互传输数据。
本文主要基于LINUX平台,对FTP客户端的实现原理进行详尽的解释并阐述如何使用C语言编写一个简单的FTP客户端。
FTP协议
相比其他协议,如HTTP协议,FTP协议要复杂一些。
与一般的C/S应用不同点在于一般的C/S应用程序一般只会建立一个Socket连接,这个连接同时处理服务器端和客户端的连接命令和数据传输。
而FTP协议中将命令与数据分开传送的方法提高了效率。
FTP使用2个端口,一个数据端口和一个命令端口(也叫做控制端口)。
这两个端口一般是21(命令端口)和20(数据端口)。
控制Socket用来传送命令,数据Socket是用于传送数据。
每一个FTP命令发送之后,FTP服务器都会返回一个字符串,其中包括一个响应代码和一些说明信息。
其中的返回码主要是用于判断命令是否被成功执行了。
命令端口
一般来说,客户端有一个Socket用来连接FTP服务器的相关端口,它负责FTP命令的发送和接收返回的响应信息。
一些操作如“登录”、“改变目录”、“删除文件”,依靠这个连接发送命令就可完成。
数据端口
对于有数据传输的操作,主要是显示目录列表,上传、下载文件,我们需要依靠另一个Socket来完成。
如果使用被动模式,通常服务器端会返回一个端口号。
客户端需要用另开一个Socket来连接这个端口,然后我们可根据操作来发送命令,数据会通过新开的一个端口传输。
如果使用主动模式,通常客户端会发送一个端口号给服务器端,并在这个端口监听。
服务器需要连接到客户端开启的这个数据端口,并进行数据的传输。
下面对FTP的主动模式和被动模式做一个简单的介绍。
主动模式(PORT)
主动模式下,客户端随机打开一个大于1024的端口向服务器的命令端口P,即21端口,发起连接,同时开放N+1端口监听,并向服务器发出“portN+1”命令,由服务器从它自己的数据端口(20)主动连接到客户端指定的数据端口(N+1)。
FTP的客户端只是告诉服务器自己的端口号,让服务器来连接客户端指定的端口。
对于客户端的防火墙来说,这是从外部到内部的连接,可能会被阻塞。
被动模式(PASV)
为了解决服务器发起到客户的连接问题,有了另一种FTP连接方式,即被动方式。
命令连接和数据连接都由客户端发起,这样就解决了从服务器到客户端的数据端口的连接被防火墙过滤的问题。
被动模式下,当开启一个FTP连接时,客户端打开两个任意的本地端口(N>1024和N+1)。
第一个端口连接服务器的21端口,提交PASV命令。
然后,服务器会开启一个任意的端口(P>1024),返回如“227enteringpassivemode(127,0,0,1,4,18)”。
它返回了227开头的信息,在括号中有以逗号隔开的六个数字,前四个指服务器的地址,最后两个,将倒数第二个乘256再加上最后一个数字,这就是FTP服务器开放的用来进行数据传输的端口。
如得到227enteringpassivemode(h1,h2,h3,h4,p1,p2),那么端口号是p1*256+p2,ip地址为h1.h2.h3.h4。
这意味着在服务器上有一个端口被开放。
客户端收到命令取得端口号之后,会通过N+1号端口连接服务器的端口P,然后在两个端口之间进行数据传输。
主要用到的FTP命令
FTP每个命令都有3到4个字母组成,命令后面跟参数,用空格分开。
每个命令都以"\r\n"结束。
要下载或上传一个文件,首先要登入FTP服务器,然后发送命令,最后退出。
这个过程中,主要用到的命令有USER、PASS、SIZE、REST、CWD、RETR、PASV、PORT、QUIT。
USER:
指定用户名。
通常是控制连接后第一个发出的命令。
“USERgaoleyi\r\n”:
用户名为gaoleyi登录。
PASS:
指定用户密码。
该命令紧跟USER命令后。
“PASSgaoleyi\r\n”:
密码为gaoleyi。
SIZE:
从服务器上返回指定文件的大小。
“SIZEfile.txt\r\n”:
如果file.txt文件存在,则返回该文件的大小。
CWD:
改变工作目录。
如:
“CWDdirname\r\n”。
PASV:
让服务器在数据端口监听,进入被动模式。
如:
“PASV\r\n”。
PORT:
告诉FTP服务器客户端监听的端口号,让FTP服务器采用主动模式连接客户端。
如:
“PORTh1,h2,h3,h4,p1,p2”。
RETR:
下载文件。
“RETRfile.txt\r\n”:
下载文件file.txt。
STOR:
上传文件。
“STORfile.txt\r\n”:
上传文件file.txt。
REST:
该命令并不传送文件,而是略过指定点后的数据。
此命令后应该跟其它要求文件传输的FTP命令。
“REST100\r\n”:
重新指定文件传送的偏移量为100字节。
QUIT:
关闭与服务器的连接。
FTP响应码
客户端发送FTP命令后,服务器返回响应码。
响应码用三位数字编码表示:
第一个数字给出了命令状态的一般性指示,比如响应成功、失败或不完整。
第二个数字是响应类型的分类,如2代表跟连接有关的响应,3代表用户认证。
第三个数字提供了更加详细的信息。
第一个数字的含义如下:
1表示服务器正确接收信息,还未处理。
2表示服务器已经正确处理信息。
3表示服务器正确接收信息,正在处理。
4表示信息暂时错误。
5表示信息永久错误。
第二个数字的含义如下:
0表示语法。
1表示系统状态和信息。
2表示连接状态。
3表示与用户认证有关的信息。
4表示未定义。
5表示与文件系统有关的信息。
Socket编程的几个重要步骤
Socket客户端编程主要步骤如下:
1.socket()创建一个Socket
2.connect()与服务器连接
3.write()和read()进行会话
4.close()关闭Socket
Socket服务器端编程主要步骤如下:
1.socket()创建一个Socket
2.bind()
3.listen()监听
4.accept()接收连接的请求
5.write()和read()进行会话
6.close()关闭Socket
实现FTP客户端上传下载功能
下面让我们通过一个例子来对FTP客户端有一个深入的了解。
本文实现的FTP客户端有下列功能:
1.客户端和FTP服务器建立Socket连接。
2.向服务器发送USER、PASS命令登录FTP服务器。
3.使用PASV命令得到服务器监听的端口号,建立数据连接。
4.使用RETR/STOR命令下载/上传文件。
5.在下载完毕后断开数据连接并发送QUIT命令退出。
本例中使用的FTP服务器为filezilla。
在整个交互的过程中,控制连接始终处于连接的状态,数据连接在每传输一个文件时先打开,后关闭。
客户端和FTP服务器建立Socket连接
当客户端与服务器建立连接后,服务器会返回220的响应码和一些欢迎信息。
图1.客户端连接到服务器端
清单1.客户端连接到FTP服务器,接收欢迎信息
SOCKETcontrol_sock;structhostent*hp;structsockaddr_inserver;memset(&server,0,sizeof(structsockaddr_in));/*初始化socket*/control_sock=socket(AF_INET,SOCK_STREAM,0);hp=gethostbyname(server_name);memcpy(&server.sin_addr,hp->h_addr,hp->h_length);server.sin_family=AF_INET;server.sin_port=htons(port);/*连接到服务器端*/connect(control_sock,(structsockaddr*)&server,sizeof(server));/*客户端接收服务器端的一些欢迎信息*/read(control_sock,read_buf,read_len);
客户端登录FTP服务器
当客户端发送用户名和密码,服务器验证通过后,会返回230的响应码。
然后客户端就可以向服务器端发送命令了。
图2.客户端登录FTP服务器
清单2.客户端发送用户名和密码,登入FTP服务器
/*命令”USERusername\r\n”*/sprintf(send_buf,"USER%s\r\n",username);/*客户端发送用户名到服务器端*/write(control_sock,send_buf,strlen(send_buf));/*客户端接收服务器的响应码和信息,正常为”331Usernameokay,needpassword.”*/read(control_sock,read_buf,read_len);/*命令”PASSpassword\r\n”*/sprintf(send_buf,"PASS%s\r\n",password);/*客户端发送密码到服务器端*/write(control_sock,send_buf,strlen(send_buf));/*客户端接收服务器的响应码和信息,正常为”230Userloggedin,proceed.”*/read(control_sock,read_buf,read_len);
客户端让FTP服务器进入被动模式
当客户端在下载/上传文件前,要先发送命令让服务器进入被动模式。
服务器会打开数据端口并监听。
并返回响应码227和数据连接的端口号。
图3.客户端让服务器进入被动模式
清单3.让服务器进入被动模式,在数据端口监听
/*命令”PASV\r\n”*/sprintf(send_buf,"PASV\r\n");/*客户端告诉服务器用被动模式*/write(control_sock,send_buf,strlen(send_buf));/*客户端接收服务器的响应码和新开的端口号,*正常为”227Enteringpassivemode(
)”*/read(control_sock,read_buf,read_len);
客户端通过被动模式下载文件
当客户端发送命令下载文件。
服务器会返回响应码150,并向数据连接发送文件内容。
图4.客户端从FTP服务器端下载文件
清单4.客户端连接到FTP服务器的数据端口并下载文件
/*连接服务器新开的数据端口*/connect(data_sock,(structsockaddr*)&server,sizeof(server));/*命令”CWDdirname\r\n”*/sprintf(send_buf,"CWD%s\r\n",dirname);/*客户端发送命令改变工作目录*/write(control_sock,send_buf,strlen(send_buf));/*客户端接收服务器的响应码和信息,正常为”250Commandokay.”*/read(control_sock,read_buf,read_len);/*命令”SIZEfilename\r\n”*/sprintf(send_buf,"SIZE%s\r\n",filename);/*客户端发送命令从服务器端得到下载文件的大小*/write(control_sock,send_buf,strlen(send_buf));/*客户端接收服务器的响应码和信息,正常为”213
客户端退出服务器
当客户端下载完毕后,发送命令退出服务器,并关闭连接。
服务器会返回响应码200。
图5.客户端从FTP服务器退出
清单5.客户端关闭数据连接,退出FTP服务器并关闭控制连接
/*客户端关闭数据连接*/close(data_sock);/*客户端接收服务器的响应码和信息,正常为”226Transfercomplete.”*/read(control_sock,read_buf,read_len);/*命令”QUIT\r\n”*/sprintf(send_buf,"QUIT\r\n");/*客户端将断开与服务器端的连接*/write(control_sock,send_buf,strlen(send_buf));/*客户端接收服务器的响应码,正常为”200Closesconnection.”*/read(control_sock,read_buf,read_len);/*客户端关闭控制连接*/close(control_sock);
至此,下载文件已经完成。
需要注意的是发送FTP命令的时候,在命令后要紧跟“\r\n”,否则服务器不会返回信息。
回车换行符号“\r\n”是FTP命令的结尾符号,当服务器接收到这个符号时,认为客户端发送的命令已经结束,开始处理。
否则会继续等待。
让我们来看一下FTP服务器这一端的响应情况:
清单6.客户端下载文件时,FTP服务器的响应输出
(notloggedin)(127.0.0.1)>Connected,sendingwelcomemessage...(notloggedin)(127.0.0.1)>220-FileZillaServerversion0.9.36beta(notloggedin)(127.0.0.1)>220hellogaoleyi(notloggedin)(127.0.0.1)>USERgaoleyi(notloggedin)(127.0.0.1)>331Passwordrequiredforgaoleyi(notloggedin)(127.0.0.1)>PASS*********gaoleyi(127.0.0.1)>230Loggedongaoleyi(127.0.0.1)>PWDgaoleyi(127.0.0.1)>257"/"iscurrentdirectory.gaoleyi(127.0.0.1)>SIZEfile.txtgaoleyi(127.0.0.1)>2134096gaoleyi(127.0.0.1)>PASVgaoleyi(127.0.0.1)>227EnteringPassiveMode(127,0,0,1,13,67)gaoleyi(127.0.0.1)>RETRfile.txtgaoleyi(127.0.0.1)>150Connectionacceptedgaoleyi(127.0.0.1)>226TransferOKgaoleyi(127.0.0.1)>QUITgaoleyi(127.0.0.1)>221Goodbye
首先,服务器准备就绪后返回220。
客户端接收到服务器端返回的响应码后,相继发送“USERusername”和“PASSpassword”命令登录。
随后,服务器返回的响应码为230开头,说明客户端已经登入了。
这时,客户端发送PASV命令让服务器进入被动模式。
服务器返回如“227EnteringPassiveMode(127,0,0,1,13,67)”,客户端从中得到端口号,然后连接到服务器的数据端口。
接下来,客户端发送下载命令,服务器会返回响应码150,并从数据端口发送数据。
最后,服务器返回“226transfercomplete”,表明数据传输完成。
需要注意的是,客户端不要一次发送多条命令,例如我们要打开一个目录并且显示这个目录,我们得发送CWDdirname,PASV,LIST。
在发送完CWDdirname之后等待响应代码,然后再发送后面一条。
当PASV返回之后,我们打开另一个Socket连接到相关端口上。
然后发送LIST,返回125之后在开始接收数据,最后返回226表明完成。
在传输多个文件的过程中,需要注意的是每次新的传输都必须重新使用PASV获取新的端口号,接收完数据后应该关闭该数据连接,这样服务器才会返回一个2XX成功的响应。
然后客户端可以继续下一个文件的传输。
上传文件与下载文件相比,登入验证和切换被动模式都如出一辙,只需要改变发送到服务器端的命令,并通过数据连接发送文件内容。
客户端通过被动模式向服务器上传文件
当客户端发送命令上传文件,服务器会从数据连接接收文件。
图6.客户端连接到FTP服务器的数据端口并上传文件
客户端通过主动模式向服务器上传文件
到目前为止,本文介绍的都是客户端用被动模式进行文件的上传和下载。
下面将介绍客户端用主动模式下载文件。
图7.用主动模式从FTP服务器下载文件
清单7.用主动模式从FTP服务器下载文件的示例C程序......SOCKETdata_sock;data_sock=socket(AF_INET,SOCK_STREAM,0);structsockaddr_inname;name.sin_family=AF_INET;name.sin_addr.s_addr=htons(INADDR_ANY);server_port=p1*256+p2;length=sizeof(name);name.sin_port=htons(server_port);bind(server_sock,(structsockaddr*)&name,length);structsockaddr_inclient_name;length=sizeof(client_name);/*客户端开始监听端口p1*256+p2*/listen(server_sock,64);/*命令”PORT\r\n”*/sprintf(send_buf,"PORT1287,0,0,1,%d,%d\r\n",p1,p2);write(control_sock,send_buf,strlen(send_buf));/*客户端接收服务器的响应码和信息,正常为”200Portcommandsuccessful”*/read(control_sock,read_buf,read_len);sprintf(send_buf,"RETRfilename.txt\r\n");write(control_sock,send_buf,strlen(send_buf));/*客户端接收服务器的响应码和信息,正常为”150Openingdatachannelforfiletransfer.”*/read(control_sock,read_buf,read_len);/*ftp客户端接受服务器端的连接请求*/data_sock=accept(server_sock,(structsockaddr*)&client_name,&length);......file_handle=open(disk_name,ROFLAGS,RWXALL);for(;;){......read(data_sock,read_buf,read_len);write(file_handle,read_buf,read_len);......}close(file_handle);
客户端通过PORT命令告诉服务器连接自己的p1*256+p2端口。
随后在这个端口进行监听,等待FTP服务器连接上来,再通过这个数据端口来传输文件。
PORT方式在传送数据时,FTP客户端其实就相当于一个服务器端,由FTP服务器主动连接自己。
断点续传
由于网络不稳定,在传输文件的过程中,可能会发生连接断开的情况,这时候需要客户端支持断点续传的功能,下次能够从上次终止的地方开始接着传送。
需要使用命令REST。
如果在断开连接前,一个文件已经传输了512个字节。
则断点续传开始的位置为512,服务器会跳过传输文件的前512字节。
清单8.从FTP服务器断点续传下载文件
....../*命令”RESToffset\r\n”*/sprintf(send_buf,"REST%ld\r\n",offset);/*客户端发送命令指定下载文件
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux FTP 编程 socket