logo资料库

使用 Socket 通信实现 FTP 客户端程序.doc

第1页 / 共17页
第2页 / 共17页
第3页 / 共17页
第4页 / 共17页
第5页 / 共17页
第6页 / 共17页
第7页 / 共17页
第8页 / 共17页
资料共17页,剩余部分请下载后查看
使用 Socket 通信实现 FTP 客户端程序
使用 Socket 通信实现 FTP 客户端程 序 高 乐怡, 软件工程师, IBM 顾 锋磊, 软件工程师, IBM 简介: FTP 客户端如 FlashFXP,File Zilla 被广泛应用,原理上都是用底层 的 Socket 来实现。FTP 客户端与服务器端进行数据交换必须建立两个套接字, 一个作为命令通道,一个作为数据通道。前者用于客户端向服务器发送命令,如 登录,删除某个文件,后者用于接收数据,例如下载或上传文件等。本文详细阐 述如何调用系统接口发送 FTP 命令实现文件上传下载等 FTP 客户端功能,让读 者对 FTP 客户端的原理有一个深入的了解。 本文的标签: ftp, linux 网络编程, network, socket, 使用, 客户端程序, 教学, 通信实现, 通用编程 标记本文! 发布日期: 2011 年 4 月 07 日 级别: 初级 访问情况 : 21274 次浏览 评论: 0 (查看 | 添加评论 - 登录) 平均分 (86 个评分) 为本文评分 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 端口监听,并向服务器发出 “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 开头的信息,在括号中有以逗号隔开的六 个数字,前四个指服务器的地址,最后两个,将倒数第二个乘 256 再加上最后 一个数字,这就是 FTP 服务器开放的用来进行数据传输的端口。如得到 227 entering passive mode (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: 指定用户名。通常是控制连接后第一个发出的命令。“USER gaoleyi\r\n”: 用户名为 gaoleyi 登录。 PASS: 指定用户密码。该命令紧跟 USER 命令后。“PASS gaoleyi\r\n”:密码 为 gaoleyi。 SIZE: 从服务器上返回指定文件的大小。“SIZE file.txt\r\n”:如果 file.txt 文件存在,则返回该文件的大小。 CWD: 改变工作目录。如:“CWD dirname\r\n”。 PASV: 让服务器在数据端口监听,进入被动模式。如:“PASV\r\n”。 PORT: 告诉 FTP 服务器客户端监听的端口号,让 FTP 服务器采用主动模式连接 客户端。如:“PORT h1,h2,h3,h4,p1,p2”。 RETR: 下载文件。“RETR file.txt \r\n”:下载文件 file.txt。 STOR: 上传文件。“STOR file.txt\r\n”:上传文件 file.txt。
REST: 该命令并不传送文件,而是略过指定点后的数据。此命令后应该跟其它要 求文件传输的 FTP 命令。“REST 100\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 服务器,接收欢迎信息 SOCKET control_sock; struct hostent *hp; struct sockaddr_in server; memset(&server, 0, sizeof(struct sockaddr_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,(struct sockaddr *)&server, sizeof(server)); /* 客户端接收服务器端的一些欢迎信息 */ read(control_sock, read_buf, read_len); 客户端登录 FTP 服务器
当客户端发送用户名和密码,服务器验证通过后,会返回 230 的响应码。然后 客户端就可以向服务器端发送命令了。 图 2. 客户端登录 FTP 服务器 清单 2. 客户端发送用户名和密码,登入 FTP 服务器 /* 命令 ”USER username\r\n” */ sprintf(send_buf,"USER %s\r\n",username); /*客户端发送用户名到服务器端 */ write(control_sock, send_buf, strlen(send_buf)); /* 客户端接收服务器的响应码和信息,正常为 ”331 User name okay, need password.” */ read(control_sock, read_buf, read_len); /* 命令 ”PASS password\r\n” */ sprintf(send_buf,"PASS %s\r\n",password); /* 客户端发送密码到服务器端 */ write(control_sock, send_buf, strlen(send_buf)); /* 客户端接收服务器的响应码和信息,正常为 ”230 User logged in, 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)); /*客户端接收服务器的响应码和新开的端口号, * 正常为 ”227 Entering passive mode ()” */ read(control_sock, read_buf, read_len); 客户端通过被动模式下载文件 当客户端发送命令下载文件。服务器会返回响应码 150,并向数据连接发送文件 内容。 图 4. 客户端从 FTP 服务器端下载文件
分享到:
收藏