1. 背景简介

最近研究如何在内网搭架FTP服务器,同时要保证外网(公网)能访问的到。终成正果,但走了一些弯路,在此记下,以飨后人。

2. 基础知识

FTP 使用 2 个端口,一个数据端口和一个命令端口(也叫做控制端口)。这两个端口一般是21 (命令端口)和 20 (数据端口),当然你也可以自定义。控制 Socket 用来传送命令,数据 Socket 是用于传送数据。每一个 FTP 命令发送之后,FTP 服务器都会返回一个字符串,其中包括一个响应代码和一些说明信息。其中的返回码主要是用于判断命令是否被成功执行了。

2.1. 命令端口

一般来说,客户端有一个 Socket用来连接 FTP 服务器的相关端口,它负责 FTP 命令的发送和接收返回的响应信息。一些操作如“登录”、“改变目录”、“删除文件”,依靠这个连接发送命令就可完成。

2.2. 数据端口

对于有数据传输的操作,主要是显示目录列表,上传、下载文件,我们需要依靠另一个 Socket来完成。

如果使用被动模式,通常服务器端会返回一个端口号。客户端需要用另开一个 Socket 来连接这个端口,然后我们可根据操作来发送命令,数据会通过新开的一个端口传输。

如果使用主动模式,通常客户端会发送一个端口号给服务器端,并在这个端口监听。服务器需要连接到客户端开启的这个数据端口,并进行数据的传输。

下面对 FTP 的主动模式和被动模式做一个简单的介绍。

2.3. 主动模式(PORT)

主动模式下,客户端随机打开一个大于1024 的端口向服务器的命令端口 P,即 21 端口,发起连接,同时开放N +1 端口监听,并向服务器发出 “port N+1” 命令,由服务器从它自己的数据端口 (20) 主动连接到客户端指定的数据端口 (N+1)。

FTP 的客户端只是告诉服务器自己的端口号,让服务器来连接客户端指定的端口。对于客户端的防火墙来说,这是从外部到内部的连接,可能会被阻塞。

2.4. 被动模式(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,然后在两个端口之间进行数据传输。

3. 我走过的弯路

使用Serv-U搭架FTP服务器很简单,网上教程也很多,不再累述。我这里只记录下我遇到的问题。

3.1. 使用环境

操作系统

FTP软件

FTP软件版本

FTP服务器

Windows XP

Serv-U

版本15.0.1.20

FTP客户端

Windows XP

FileZilla

版本3.8.0

FTP服务器安装在公司内网的电脑上,FTP客户端在外网的电脑上(严格来说也是在另一外局域网内)。

3.2. PASV端口范围

被动模式(PASV)下,有数据要传输时,服务器会打开一个数据端口(并处于监听状态),然后告知客户端,客户端连接这个数据端口发送数据。但是数据端口是随机的,那么服务器该如何将这些随机数据端口映射到公网的路由器上呢???总不能让内部网的一台机器完全暴露到公网上吧,虽然确实有这样的方案(称之为DMZ主机),但这绝对是最愚蠢的选择。

这就是我遇到的第一个弯路,折腾了很久才知道。虽然数据端口是随机的,但Serv-U可以指定随机的范围。打开Serv-U管理控制台 > 管理服务器 > 服务器限制和设置 > 服务器设置 。在“设置”选项卡里找到“PASV端口范围”,如下图所示,在这里就可以指定随见的范围了。你只要把这些端口映射到路由器就可以了。

图表 1 PASV 端口范围

当然别忘了,还有一个命令端口也得映射。

3.3. PASV IP地址

我遇到的第二个难缠的问题是,FileZilla客户端获取不到FTP服务器的目录列表。日志信息如下:

状态:    正在连接 125.89.123.99:13000...

状态:    连接建立,等待欢迎消息...

响应:    220 Serv-U FTP Server v15.0 ready...

命令:    USER zhangsan

响应:    331 User name okay, need password.

命令:    PASS ***

响应:    230 User logged in, proceed.

命令:    CLNT FileZilla

响应:    200 Noted.

命令:    OPTS UTF8 ON

响应:    200 OPTS UTF8 is set to ON.

命令:    OPTS MLST type;size;modify;perm;

响应:    200 MLST OPTS Type;Size;Modify;Perm;

状态:    已连接

状态:    读取目录列表...

命令:    PWD

响应:    257 "/" is current directory.

命令:    TYPE I

响应:    200 Type set to I.

命令:    PASV

响应:    227 Entering Passive Mode (100,100,100,100,50,203)

命令:    MLSD

响应:    150 Opening BINARY mode data connection for MLSD.

错误:    连接超时

错误:    读取目录列表失败

也是经过一阵折腾,最后突然发现服务器对PASV指令的响应是:227Entering Passive Mode (100,100,100,100,50,203),这里100.100.100.100是FTP服务器在内网IP,客户端自然连接不上。打开Serv-U管理控制台 > 你自定义的域名 > 域详细信息 > 监听器 > 编辑 ,在PASV IP地址或域名中设置公网IP即可。 如下图所示。

4. 总结

FTP服务器至少需要两个端口:命令端口和数据端口。命令端口是固定的,而数据端口是随机的。随机的端口如何映射到公网?Serv-U可以设置PASV端口范围,随机也只是在设定的范围内随机。另外需要设置PASV IP地址,否者服务器响应客户端的PASV 命令时,会把服务器在内网中的IP地址告知客户端,这个地址对应客户端来说是连接不上的。

 

引用: http://blog.csdn.net/benkaoya/article/details/24480411

Serv-u 外网访问内网的FTP服务器的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  3. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  4. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  5. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  6. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  7. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  8. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  9. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

  10. 怎样从外网访问内网Tornado

    外网访问内网Tornado 本地安装了Tornado,只能在局域网内访问,怎样从外网也能访问本地Tornado? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Tornado 默认安装 ...

随机推荐

  1. SparseArray具体解释,我说SparseArray,你说要!

    可能在Android 中使用HashMap 的时候看到过提示. HashMap<Integer,Bitmap> mp = new HashMap<Integer,Bitmap> ...

  2. html 常用

    1. var canvas = document.getElementById("tutorial"); var ctx = canvas.getContext("2d& ...

  3. [浪风推荐]javascritp中倒计定时器和循环定时器

    在javascritp中,有两个关于定时器的专用函数,分别为: 1.倒计定时器:timename=setTimeout(“function();”,delaytime); 2.循环定时器:timena ...

  4. 在DLL中动态加载其所依赖的dll

    windows下LoadLibrary函数的搜索顺序是先搜索system32等系统环境变量path下注册过的路径,然后是当前路径. 这里的相对路径是指的主exe所在路径,并且相对路径在程序运行过程中可 ...

  5. 将场景导出XML或JSON或二进制而且解析还原场景

    导出unity场景的全部游戏对象信息,一种是XML一种是JSON. 本篇文章我们把游戏场景中游戏对象的.旋转.缩放.平移与Prefab的名称导出在XML与JSON中.然后解析刚刚导出的XML或JSON ...

  6. SQL.Cookbook 读书笔记2 查询结果排序

    第二章 查询结果排序 2.1 按查询字段排序 order by sal asc; desc;-- 3表示sal 2.2 按子串查询 );--按job的最后两个字符排序 2.3 对字符数字混合排序 cr ...

  7. Eclipse: Android Device Chooser - Unknown Target

    公司最近所有的项目都使用到了Android开发手机(或PDA)应用.所需要的Android开发技术并不是非常复杂,因为我们的底层方法全部使用WebServcie写好了,做Android开发的人员只需要 ...

  8. 【BZOJ4974】字符串大师 KMP

    [BZOJ4974]字符串大师 Description 一个串T是S的循环节,当且仅当存在正整数k,使得S是T^k(即T重复k次)的前缀,比如abcd是abcdabcdab的循环节.给定一个长度为n的 ...

  9. mongodb安全配置

    1. 为数据库增加管理员 use admin db.createUser({ >user:'userName', pwd:'password', roles:[{role:'userAdminA ...

  10. Null Coalescing Operator

    w Parse error: syntax error, unexpected '?'