世界上最伟大的投资就是投资自己的教育

全场限时 5 折

首页Ruby
Mikasa·Ackerman · 真仙

如何在 Rails 实现一个 ftp 连接池

Mikasa·Ackerman发布于5424 次阅读

需求背景:

项目中使用 Net::FTP 上传文件到服务器,有时候会出现一次性上传几十到几百不等的文件,每次上传一个文件都要 执行:

1.创建 client

2.连接

3.登录

4.上传文件

5.关闭 client

目标:

希望能像 ftp 软件类似 filezilla 一样,当同时上传 10 个文件时,只登陆一次,上传完毕后在下线(或者被服务器踢掉)

想法:

1.实现一个连接池

require 'net/ftp'

# 单例类 保证当程序运行时访问的连接池只有一个
class FtpPool
  include Singleton

  attr_accessor :connections

  semaphore = Mutex.new

  def initialize
    @connections = {}
  end

  def get_connection(ftp_server)
    key = "#{ftp_server.address}#{ftp_server.port}#{ftp_server.username}"

    # 线程加锁,保证同样的key只有一个连接 
    semaphore.synchronize{
      client = @connections[key] || @connections[key] = Net::FTP.new
    }

    begin
      client.noop
    rescue Exception : e
      reconnect(ftp_server, client)
    end
    client
  end

 # 重新连接 
 def reconnect(ftp_server, client)
   client.connect(ftp_server.address, ftp_server.port)
   client.login(ftp_server.username, ftp_server.password)
 end

end

这里假设传入一个 ftpserver 附带四个属性 分别是地址,端口,账号和密码;
用前三个属性简单的生成一个 key 测试一下

首先生成一个 ftp_pool

pry(main)> ftp_pool = FtpPool.instance
: #<FtpPool:0x007fba931af310 @connections={}>

然后调用 get_connection 从连接池中获取一个连接,如果没有就新建一个

ftp_pool.get_connection(ftp_server)
: #<Net::FTP:0x007fa1502147a8
 @binary=true,
 @debug_mode=false,
 @last_response="200 OK\n",
 @last_response_code="200",
 @logged_in=true,
 @mon_count=0,
 @mon_mutex=#<Thread::Mutex:0x007fa150214708>,
 @mon_owner=nil,
 @open_timeout=nil,
 @passive=true,
 @read_timeout=60,
 @resume=false,
 @sock=#<Net::FTP::BufferedSocket io=#<TCPSocket:0x007fa1511cf918>>,
 @welcome="230 Logged on\n">

这样我们就获得了一个 Net::FTP 的 client
可以使用然后我们用这个 client 发送文件到 ftp 服务器,如果发送失败通过抓取异常,
如果异常是未连接或者未登录,就重新执行连接和登录名令后在发送文件即可。
这样一个简单的 ftp_pool 就可以运行了

本站文章均为原创内容,如需转载请注明出处,谢谢。

0 条回复
暂无回复~~
喜欢
统计信息
    学员: 29226
    视频数量: 1985
    文章数量: 489

© 汕尾市求知科技有限公司 | Rails365 Gitlab | Qiuzhi99 Gitlab | 知乎 | b 站 | 搜索

粤公网安备 44152102000088号粤公网安备 44152102000088号 | 粤ICP备19038915号

Top