「C Sharpとネットワーク - FTP」の版間の差分

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動
(ページの作成:「== 概要 == FTP (File Transfer Protocol) は、インターネットを介してファイルを転送するために使用される標準的なネットワークプロトコルである。<br> 1971年に開発され、現在でも広く使用されている。<br> <br> FTPの主な目的は、クライアントとサーバ間でのファイルの送受信を可能にすることである。<br> これは、Webサイトの更新、大容量ファイルの共有、…」)
 
161行目: 161行目:
       // バイナルモード送信 (画像ファイル等のバイナリファイル向け)
       // バイナルモード送信 (画像ファイル等のバイナリファイル向け)
       await ftpTransfer.UploadFileAsync("localImageFile.jpg", "remoteImageFile.jpg", false);
       await ftpTransfer.UploadFileAsync("localImageFile.jpg", "remoteImageFile.jpg", false);
    }
}
</syntaxhighlight>
<br><br>
== FTP : データの受信 ==
以下の例では、FTPを使用して、ASCIIモード (テキストファイル) とバイナリモード (画像ファイル等) で複数のファイルを同時に受信している。<br>
<br>
<u>※注意</u><br>
<u>サーバによっては、同時接続数に制限がある場合があるため、FTPサーバの同時接続数制限に注意すること。</u><br>
<br>
<u>また、大量のファイルをダウンロードする場合は、メモリ使用量に注意すること。</u><br>
<u>必要に応じて、ダウンロードをバッチ処理することを検討する。</u><br>
<br>
<syntaxhighlight lang="c#">
using System;
using System.IO;
using System.Net;
using System.Collections.Generic;
using System.Threading.Tasks;
class AsyncFtpFileDownload
{
    private string host;
    private string username;
    private string password;
    // FTP接続に必要な情報
    public AsyncFtpFileDownload(string host, string username, string password)
    {
      this.host = host;
      this.username = username;
      this.password = password;
    }
    // 単一のファイルを非同期でダウンロード
    public async Task DownloadFileAsync(string remoteFilePath, string localFilePath, bool useAscii)
    {
      try
      {
          // FTP要求の作成
          FtpWebRequest request = (FtpWebRequest)WebRequest.Create($"ftp://{host}/{remoteFilePath}");
          request.Method = WebRequestMethods.Ftp.DownloadFile;  // ファイルの受信
          request.Credentials = new NetworkCredential(username, password);
          request.UsePassive  = true;      // パッシブモードを使用するかどうかの可否
          request.UseBinary  = !useAscii;  // ASCIIモードとバイナリモードの切り替え
          request.KeepAlive  = false;
          using (FtpWebResponse response = (FtpWebResponse)await request.GetResponseAsync())
          using (Stream ftpStream = response.GetResponseStream())
          using (FileStream fileStream = File.Create(localFilePath))
          {
            // ファイルは10[KB]のバッファを使用して読み取り、FTPストリームに書き込む
            byte[] buffer = new byte[10240];
            int read;
            while ((read = await ftpStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
            {
                await fileStream.WriteAsync(buffer, 0, read);
            }
            Console.WriteLine($"ファイルの受信が完了: {remoteFilePath} -> {localFilePath}");
            Console.WriteLine($"ステータス: {response.StatusDescription}");
          }
      }
      catch (WebException ex)
      {
          FtpWebResponse response = (FtpWebResponse)ex.Response;
          if (response != null)
          {
            Console.WriteLine($"FTP受信エラー: {response.StatusDescription}");
          }
          else
          {
            Console.WriteLine($"Web例外が発生: {ex.Message}");
          }
      }
      catch (Exception ex)
      {
          Console.WriteLine($"予期せぬエラーが発生: {ex.Message}");
      }
    }
    // 複数のファイルを同時に非同期でダウンロードするメソッド
    public async Task DownloadMultipleFilesAsync(List<(string remoteFilePath, string localFilePath, bool useAscii)> files)
    {
      List<Task> downloadTasks = new List<Task>();
      // 各ファイルのダウンロードタスクを生成して、リストに追加
      foreach (var file in files)
      {
          downloadTasks.Add(DownloadFileAsync(file.remoteFilePath, file.localFilePath, file.useAscii));
      }
      // 全てのダウンロードタスクが完了するまで待機
      await Task.WhenAll(downloadTasks);
      Console.WriteLine("全てのファイルの受信が完了");
    }
    public static async Task Main()
    {
      // FTP接続情報
      string host    = "<ホスト名またはIPアドレス  例: ftp.example.com>";
      string username = "<ユーザ名>";
      string password = "<パスワード>";
      AsyncFtpFileDownload ftpDownload = new AsyncFtpFileDownload(host, username, password);
      // 受信するファイル群
      List<(string remoteFilePath, string localFilePath, bool useAscii)> filesToDownload = new List<(string, string, bool)>
      {
          ("remoteTextFile1.txt", "localTextFile1.txt", true),  // テキストファイル(ASCIIモード)
          ("remoteTextFile2.txt", "localTextFile2.txt", true),  // テキストファイル(ASCIIモード)
          ("remoteImageFile1.jpg", "localImageFile1.jpg", false),  // 画像ファイル(バイナリモード)
          ("remoteImageFile2.jpg", "localImageFile2.jpg", false)  // 画像ファイル(バイナリモード)
      };
      // 複数のファイルを同時に受信
      await ftpDownload.DownloadMultipleFilesAsync(filesToDownload);
     }
     }
  }
  }

2024年9月13日 (金) 17:40時点における版

概要

FTP (File Transfer Protocol) は、インターネットを介してファイルを転送するために使用される標準的なネットワークプロトコルである。
1971年に開発され、現在でも広く使用されている。

FTPの主な目的は、クライアントとサーバ間でのファイルの送受信を可能にすることである。
これは、Webサイトの更新、大容量ファイルの共有、バックアップの作成等の用途に利用されている。

FTPの動作原理は、クライアント-サーバモデルに基づいており、
クライアントがFTPサーバに接続および認証を行った後、ファイルの転送やディレクトリの操作等のコマンドを実行する。

一般的に、FTPは2つの接続を使用する。

  • 制御接続
    コマンドの送信
  • データ接続
    ファイル転送


セキュリティの観点から見ると、従来のFTPでは、データが平文で送信されるため、盗聴のリスクがある。
この問題に対処するため、FTPSやSFTP等の暗号化された代替プロトコルが開発された。

しかし、FTPは柔軟性が高く、様々な転送モードをサポートしている。
アスキーモードはテキストファイル、バイナリモードは画像や実行可能ファイルに適している。

多くのFTPクライアントソフトウェアが存在しており、グラフィカルなインターフェースを提供しているため、一般ユーザでも簡単に使用することができる。
また、コマンドラインインターフェースでも使用可能であり、高度なユーザや自動化スクリプトに適している。

FTPは長年にわたり使用されてきたが、セキュリティ上の懸念やより新しい代替手段の登場により、その使用は徐々に減少している。
しかし、特定の状況下では依然として有効なプロトコルとして認識されている。


アクティブモードとパッシブモード

FTPには、アクティブモードとパッシブモードの2つの接続モードが存在する。

アクティブモード

クライアントがデータ接続のためのポートを開き、サーバに接続を要求する。

ファイアウォールの問題が発生しやすく、特にNAT環境では問題が起きやすい。

パッシブモード

サーバがデータ接続のためのポートを開き、クライアントがそのポートに接続する。

ファイアウォールやNAT環境での問題が少なく、より信頼性が高い。

一般的に、パッシブモードの使用が推奨される。
特に、クライアントがファイアウォールの内側にある場合やインターネットを介して接続する場合に有効である。

ただし、特定のネットワーク環境や要件によっては、アクティブモードが必要になる場合もある。

パッシブモードのメリットを以下に示す。

  • クライアント側のファイアウォール設定が簡単である。
  • NATやプロキシを通した接続が容易である。
  • 多くの現代的なFTPクライアントのデフォルト設定である。


※注意
サーバ側で追加のポート開放が必要な場合がある。
一部の古いFTPサーバではサポートされていない可能性がある。

C#での使用例

FtpWebRequestクラスのUsePassiveプロパティを設定することにより、パッシブモードの可否を指定する。

  • trueに指定する場合
    パッシブモードを使用する。
  • falseに指定する場合
    アクティブモードを使用する。


 FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpUrl);
 request.UsePassive = true;  // パッシブモードを有効化



FTP : データの送信

以下の例では、FTPを使用して、ASCIIモード (テキストファイル) とバイナリモード (画像ファイル等) でファイルを送信している。

FTP接続にはIPアドレスも使用可能である。
IPアドレスを使用するメリットと注意点を以下に示す。

  • IPアドレスを使用する場合のメリット
    • 直接接続
      DNSルックアップが不要なため、接続が少し速くなる可能性がある。
  • ネットワークトラブルシューティング
    • DNSの問題を切り分けることができる。
    • ファイアウォール設定
      特定のIPアドレスのみを許可するようなセキュリティ設定が容易である。

  • IPアドレスを使用する場合の注意点
    • SSL / TLS証明書
      セキュアな接続 (FTPS) を使用する場合、証明書がIPアドレスに対して発行されていないと警告が出る可能性がある。
    • 柔軟性
      サーバのIPアドレスが変更された場合、クライアント側の設定も変更が必要になる。
    • 仮想ホスティング
      1つのIPアドレスで複数のFTPサーバをホストしている場合、正しいサーバに接続できない可能性がある。


セキュリティを向上させるために、可能であればFTPSやSFTP等の暗号化されたプロトコルを使用することを推奨する。

 using System;
 using System.IO;
 using System.Net;
 using System.Threading.Tasks;
 
 class AsyncFtpFileTransfer
 {
    private string host;
    private string username;
    private string password;
 
    // FTP接続に必要な情報
    public AsyncFtpFileTransfer(string host, string username, string password)
    {
       this.host     = host;
       this.username = username;
       this.password = password;
    }
 
    // ローカルファイルパス、リモートファイルパス、アスキーモードの可否を設定して、FTPサーバへ送信
    public async Task UploadFileAsync(string localFilePath, string remoteFilePath, bool useAscii)
    {
       try
       {
          FtpWebRequest request = (FtpWebRequest)WebRequest.Create($"ftp://{host}/{remoteFilePath}");
          request.Method      = WebRequestMethods.Ftp.UploadFile;  // ファイルの送信
          request.Credentials = new NetworkCredential(username, password);
          request.UsePassive  = true;       // パッシブモードを使用するかどうかの可否
          request.UseBinary   = !useAscii;  // ASCIIモードとバイナリモードの切り替え
          request.KeepAlive   = false;
 
          using (FileStream fileStream = File.OpenRead(localFilePath))
          using (Stream ftpStream = await request.GetRequestStreamAsync())
          {
             // ファイルは10[KB]のバッファを使用して読み取り、FTPストリームに書き込む
             byte[] buffer = new byte[10240];
             int read;
             while ((read = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
             {
                await ftpStream.WriteAsync(buffer, 0, read);
             }
          }
 
          Console.WriteLine($"Fileの送信に成功: {localFilePath} -> {remoteFilePath}");
       }
       catch (WebException ex)
       {
          FtpWebResponse response = (FtpWebResponse)ex.Response;
          Console.WriteLine($"FTP送信エラー: {response.StatusDescription}");
       }
       catch (Exception ex)
       {
          Console.WriteLine($"予期しないエラーが発生: {ex.Message}");
       }
    }
 
    public static async Task Main()
    {
       string host     = "<ホスト名またはIPアドレス  例1: ftp.example.com,  例2: 192.168.1.100>";
       string username = "<ユーザ名>";
       string password = "<パスワード>";
 
       AsyncFtpFileTransfer ftpTransfer = new AsyncFtpFileTransfer(host, username, password);
 
       // ASCIIモード送信 (テキストファイル向け)
       await ftpTransfer.UploadFileAsync("localTextFile.txt", "remoteTextFile.txt", true);
 
       // バイナルモード送信 (画像ファイル等のバイナリファイル向け)
       await ftpTransfer.UploadFileAsync("localImageFile.jpg", "remoteImageFile.jpg", false);
    }
 }



FTP : データの受信

以下の例では、FTPを使用して、ASCIIモード (テキストファイル) とバイナリモード (画像ファイル等) で複数のファイルを同時に受信している。

※注意
サーバによっては、同時接続数に制限がある場合があるため、FTPサーバの同時接続数制限に注意すること。

また、大量のファイルをダウンロードする場合は、メモリ使用量に注意すること。
必要に応じて、ダウンロードをバッチ処理することを検討する。

 using System;
 using System.IO;
 using System.Net;
 using System.Collections.Generic;
 using System.Threading.Tasks;
 
 class AsyncFtpFileDownload
 {
    private string host;
    private string username;
    private string password;
 
    // FTP接続に必要な情報
    public AsyncFtpFileDownload(string host, string username, string password)
    {
       this.host = host;
       this.username = username;
       this.password = password;
    }
 
    // 単一のファイルを非同期でダウンロード
    public async Task DownloadFileAsync(string remoteFilePath, string localFilePath, bool useAscii)
    {
       try
       {
          // FTP要求の作成
          FtpWebRequest request = (FtpWebRequest)WebRequest.Create($"ftp://{host}/{remoteFilePath}");
          request.Method = WebRequestMethods.Ftp.DownloadFile;  // ファイルの受信
          request.Credentials = new NetworkCredential(username, password);
          request.UsePassive  = true;      // パッシブモードを使用するかどうかの可否
          request.UseBinary   = !useAscii;  // ASCIIモードとバイナリモードの切り替え
          request.KeepAlive   = false;
 
          using (FtpWebResponse response = (FtpWebResponse)await request.GetResponseAsync())
          using (Stream ftpStream = response.GetResponseStream())
          using (FileStream fileStream = File.Create(localFilePath))
          {
             // ファイルは10[KB]のバッファを使用して読み取り、FTPストリームに書き込む
             byte[] buffer = new byte[10240];
             int read;
             while ((read = await ftpStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
             {
                await fileStream.WriteAsync(buffer, 0, read);
             }
 
             Console.WriteLine($"ファイルの受信が完了: {remoteFilePath} -> {localFilePath}");
             Console.WriteLine($"ステータス: {response.StatusDescription}");
          }
       }
       catch (WebException ex)
       {
          FtpWebResponse response = (FtpWebResponse)ex.Response;
          if (response != null)
          {
             Console.WriteLine($"FTP受信エラー: {response.StatusDescription}");
          }
          else
          {
             Console.WriteLine($"Web例外が発生: {ex.Message}");
          }
       }
       catch (Exception ex)
       {
          Console.WriteLine($"予期せぬエラーが発生: {ex.Message}");
       }
    }
 
    // 複数のファイルを同時に非同期でダウンロードするメソッド
    public async Task DownloadMultipleFilesAsync(List<(string remoteFilePath, string localFilePath, bool useAscii)> files)
    {
       List<Task> downloadTasks = new List<Task>();
 
       // 各ファイルのダウンロードタスクを生成して、リストに追加
       foreach (var file in files)
       {
          downloadTasks.Add(DownloadFileAsync(file.remoteFilePath, file.localFilePath, file.useAscii));
       }
 
       // 全てのダウンロードタスクが完了するまで待機
       await Task.WhenAll(downloadTasks);
       Console.WriteLine("全てのファイルの受信が完了");
    }
 
    public static async Task Main()
    {
       // FTP接続情報
       string host     = "<ホスト名またはIPアドレス  例: ftp.example.com>";
       string username = "<ユーザ名>";
       string password = "<パスワード>";
 
       AsyncFtpFileDownload ftpDownload = new AsyncFtpFileDownload(host, username, password);
 
       // 受信するファイル群
       List<(string remoteFilePath, string localFilePath, bool useAscii)> filesToDownload = new List<(string, string, bool)>
       {
          ("remoteTextFile1.txt", "localTextFile1.txt", true),  // テキストファイル(ASCIIモード)
          ("remoteTextFile2.txt", "localTextFile2.txt", true),  // テキストファイル(ASCIIモード)
          ("remoteImageFile1.jpg", "localImageFile1.jpg", false),  // 画像ファイル(バイナリモード)
          ("remoteImageFile2.jpg", "localImageFile2.jpg", false)   // 画像ファイル(バイナリモード)
       };
 
       // 複数のファイルを同時に受信
       await ftpDownload.DownloadMultipleFilesAsync(filesToDownload);
    }
 }