FLYING

/* TODO: 気の利いた説明を書く */

レジューム可能なファイル交換スクリプト

一対一でファイルを送ってもらっていたんだけど、途中で接続が切れて中途半端なファイルができちゃったよママン、ってな状況で役立つかもしれないスクリプト。ただし、ファイルを送信する人が開放済みのポートを持っていて、すぐに連絡を取れるような条件でないと使えないと思われ。

うさげ

クライアント側に既にファイルが存在するときは途中からダウンロードを行い、存在しないときは普通にダウンロードを行う。クライアントは指定したファイルを受信すると終了するが、サーバは何度でも接続を受け付けることができる。サーバの終了は Ctrl+C でおk。

# クライアント側
ruby resume.rb [サーバのアドレス] [サーバのポート] [受信したいファイル名]
# サーバ側
ruby resume.rb [待ち受けするポート]

ソース

#!/usr/local/bin/ruby
require 'socket'

case ARGV.size
when 1 then
  $port = ARGV[0]
when 3 then
  $addr, $port, $path = ARGV[0], ARGV[1], ARGV[2]
else
  puts("<Usage>")
  puts("client: resume.rb server_addr server_port filename")
  puts("server: resume.rb listen_port")
  exit
end

def client(sock)
  puts("connected!")
  sock.puts($path)
  File.open($path, File::WRONLY | File::CREAT | File::BINARY) {|f|
    # ポインタ移動
    f.seek(0, IO::SEEK_END)
    pos = f.tell.to_i
    sock.puts(pos)
    # レジューム
    puts("receiving #{$path} from #{pos}")
    while buf = sock.read(65536) do
      f.write(buf)
    end
  }
  puts("complete!")
end

def server(sock)
  puts("accepted!")
  $path = sock.gets.chop
  File.open($path, "rb") {|f|
    # ポインタ移動
    pos = sock.gets.chop.to_i
    f.seek(pos, IO::SEEK_SET)
    # レジューム
    puts("sending #{$path} from #{pos}")
    while buf = f.read(65536) do
      sock.write(buf)
    end
  }
  puts("complete!")
end

if $addr then
  begin
    puts("starting client")
    sock = TCPSocket.open($addr, $port)
    client(sock)
  rescue
    puts($!)
  ensure
    sock.close if sock
  end
else
  begin
    puts("starting server")
    s = TCPServer.open($port)
    while sock = s.accept do
      begin
        server(sock)
      rescue
        puts($!)
      ensure
        sock.close
      end
    end
  rescue
    puts($!)
  ensure
    s.close if s
  end
end