C#でリモートのMySQLやSSH接続をやってみた

C#でリモートのMySQLやSSH接続をやってみた

こんにちは、大阪スタジオ ソフトウェアエンジニアの滝です。
今回のお話は、C#でMySQLに接続してデータを取得したり、SSH接続でコマンドの送信をやってみたお話になります。

きっかけは、業務で集計ツールを作成する機会があり、その要件は、Windows環境からターミナルを使わずに、データベース及びログサーバーからデータ集計を行い、その結果をExcelファイルに出力するというものです。
実現には様々な方法が考えられますが、今回はWindows環境から行いたいということだったため、デスクトップクライアントを作成し、アプリケーションを実行することで集計処理を自動で行ない、結果をExcelファイルに出力するようなツールを作成することにしました。
要件を満たすために、C#でMySQLに接続してデータを取得したり、SSH接続でコマンドの送信を行う必要があり、どのように実現したかを簡単なサンプルコードと共に紹介させていただきます。

プロジェクトはコンソールアプリでもフォームアプリでもどちらでも動作します。
対応プラットフォームなど、詳しい情報は以下のリンクから確認できます。

 

今回使うライブラリ

・SSH.NET (github)
https://github.com/sshnet/SSH.NET

・MySQL(github)
https://dev.mysql.com/doc/connector-net/en/

 

SSH接続のやりかた

  • 必要なもの
    • SSH接続が可能なリモート環境(物理マシンでもVMでもOK)
      • 記事内で使用している環境はLinux CentOS 6.9(VirtualBox使用)
    • VisualStudio(どのエディションでも可)
      • 記事内で使用している開発環境はVisualStudio2017
  1. 新しいプロジェクトを作成または既存のプロジェクトを読み込む
    このサンプルではConnectSSHというプロジェクトをコンソールプロジェクトで作成しました。
    既存のプロジェクトでテストしていただいても問題ありませんが、できれば新規作成をおすすめします。

  2. NuGetからSSH.NETの追加
    図のように、ソリューションエクスプローラー内で1で作成したプロジェクト名の項目を右クリックし、NuGetパッケージの管理をクリックします。参照タブをクリックし、検索フォームに「SSH.NET」と入力し検索します。Renci製のSSH.NETをプロジェクトにインストールします

  3. とりあえず接続してみる
    以下にサンプルコードを記載します。コードの説明はコメントに書いております。

    using System;
    using Renci.SshNet;
    
    namespace RemoteServerConnect
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    // 接続先のホスト名またはIPアドレス
                    var hostNameOrIpAddr = "192.168.xxx.xxx";
    
                    // 接続先のポート番号
                    var portNo = 22;
    
                    // ログインユーザー名
                    var userName = "taki";
    
                    // ログインパスワード
                    var passWord = "xxxxxxxxxx";
    
                    // コネクション情報
                    ConnectionInfo info = new ConnectionInfo(hostNameOrIpAddr, portNo, userName,
                        new AuthenticationMethod[] {
                            new PasswordAuthenticationMethod(userName, passWord)
                            /* PrivateKeyAuthenticationMethod("キーの場所")を指定することでssh-key認証にも対応しています */
                        }
                    );
    
                    // クライアント作成
                    SshClient ssh = new SshClient(info);
    
                    // 接続開始
                    ssh.Connect();
    
                    if(ssh.IsConnected)
                    {
                        // 接続に成功した(接続状態である)
                        Console.WriteLine("[OK] SSH Connection succeeded!!");
                    }
                    else
                    {
                        // 接続に失敗した(未接続状態である)
                        Console.WriteLine("[NG] SSH Connection failed!!");
                        return;
                    }
    
                    // 接続終了
                    ssh.Disconnect();
                }
                catch(Exception ex)
                {
                    // エラー発生時
                    Console.WriteLine(ex);
                    throw ex;
                }
                
            }
        }
    }
    

    パスワード認証でSSH接続をしてみた例になります。
    接続できない場合は、ファイアウォールやポートフォワーディング設定など、ネットワーク接続自体に問題がないかを確認してみてください。

  4. コマンドを送信してみる(リモートマシンの時間を取得)
    using System;
    using Renci.SshNet;
    
    namespace RemoteServerConnect
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    // 接続先のホスト名またはIPアドレス
                    var hostNameOrIpAddr = "192.168.xxx.xxx";
    
                    // 接続先のポート番号
                    var portNo = 22;
    
                    // ログインユーザー名
                    var userName = "taki";
    
                    // ログインパスワード
                    var passWord = "xxxxxxxxxxxxxx";
    
                    // コネクション情報
                    ConnectionInfo info = new ConnectionInfo(hostNameOrIpAddr, portNo, userName,
                        new AuthenticationMethod[] {
                            new PasswordAuthenticationMethod(userName, passWord)
                            /* PrivateKeyAuthenticationMethod("キーの場所")を指定することでssh-key認証にも対応しています */
                        }
                    );
    
                    // クライアント作成
                    SshClient ssh = new SshClient(info);
    
                    // 接続開始
                    ssh.Connect();
    
                    if(ssh.IsConnected)
                    {
                        // 接続に成功した(接続状態である)
                        Console.WriteLine("[OK] SSH Connection succeeded!!");
                    }
                    else
                    {
                        // 接続に失敗した(未接続状態である)
                        Console.WriteLine("[NG] SSH Connection failed!!");
                        return;
                    }
    
                    // 送信したいコマンドを変数に入れる
                    var commandString = "date";
    
                    // コマンドを作成する
                    SshCommand cmd = ssh.CreateCommand(commandString);
    
                    // コマンドを実行する
                    Console.WriteLine("[CMD] {0}", commandString);
                    cmd.Execute();
    
                    // 結果を変数に入れる
                    var stdOut = cmd.Result;
                    var stdErr = cmd.Error;
    
                    // 終了コードを表示する
                    Console.WriteLine("終了コード:{0}", cmd.ExitStatus);
    
                    // 標準出力を表示する
                    if (stdOut != string.Empty)
                    {
                        Console.WriteLine("標準出力:");
                        Console.WriteLine(stdOut);
                        Console.WriteLine("---------");
                    }
    
                    // エラー出力を表示する
                    if (cmd.ExitStatus != 0 && stdErr != string.Empty)
                    {
                        Console.WriteLine("標準エラー出力:");
                        Console.WriteLine(stdErr);
                        Console.WriteLine("----------------");
                    }
    
                    // 接続終了
                    ssh.Disconnect();
                }
                catch(Exception ex)
                {
                    // エラー発生時
                    Console.WriteLine(ex);
                    throw ex;
                }           
            }
        }
    }
    

    今回はサンプルとして、リモート側の時間を取得してコンソールに表示するサンプルを作ってみました。

  5. こんなことに使えます
    SSHをターミナル以外のWindowsクライアントから送信するという事自体が滅多にないことだとは思いますが
    Webクライアントが使えない環境や、サーバーへのSSHアクセスはさせたいがコマンドをテンプレート化して使用させるなどの制限をしたい場合などに使えるかもしれません。
    もちろん、このライブラリを使ってターミナルクライアントを作ることも可能だと思います。

MySQL接続のやりかた

  • 必要なもの
    • MySQLサーバーが起動していて接続が可能なリモート環境(物理マシンでもVMでもOK)
      • 記事内で使用している環境はLinux CentOS 6.9 / MySQL5.5.50(VirtualBox使用)
    • VisualStudio(どのエディションでも可)
      • 記事内で使用している開発環境はVisualStudio2017
  1. 新しいプロジェクトを作成または既存のプロジェクトを読み込む
    このサンプルではConnectMysqlというプロジェクトをコンソールプロジェクトで作成しました。
    既存のプロジェクトでテストしていただいても問題ありませんが、できれば新規作成をおすすめします。

  2. NuGetからMysql.Dataの追加
    図のように、ソリューションエクスプローラー内で1で作成したプロジェクト名の項目を右クリックし、NuGetパッケージの管理をクリックします。参照タブをクリックし、検索フォームに「Mysql」と入力し検索します。
    Oracle製のMysql.Dataをプロジェクトにインストールします。

  3. とりあえず接続してみる
    以下にサンプルコードを記載します。コードの説明はコメントに書いております。

    using System;
    using MySql.Data.MySqlClient;
    
    namespace ConnectMysql
    {
        class Program
        {
            static void Main(string[] args)
            {
                // 接続に必要なパラメータ文字列を生成する
                var connectionParams = string.Format(
                    "host={0}; userid={1}; password={2}; database={3}; charset={4}",
                    "192.168.xxx.xxx",
                    "taki",
                    "xxxxxxxxxxxx",
                    "sample_db",
                    "utf8"
                );
    
                // コネクターを作成
                var mysql = new MySqlConnection(connectionParams);
    
                try
                {
                    // 接続開始
                    mysql.Open();
                }
                catch (MySqlException ex)
                {
                    // 何らかの理由で接続に失敗した
                    Console.WriteLine(ex);
                    throw ex;
                }
            }
        }
    }
    

    リモートにインストールされたMySQLサーバーにアクセスする例になります。
    接続できない場合は、MySQLユーザーのアクセス権、ファイアウォールやポートフォワーディング設定など、設定に問題がないかを確認してみてください。

  4. insertとselectをしてみる
    using System;
    using MySql.Data.MySqlClient;
    
    namespace ConnectMysql
    {
        class Program
        {
            static void Main(string[] args)
            {
                // 接続に必要なパラメータ文字列を生成する
                var connectionParams = string.Format(
                    "host={0}; userid={1}; password={2}; database={3}; charset={4}",
                    "192.168.xxx.xxx",
                    "taki",
                    "xxxxxxxxxxx",
                    "sample_db",
                    "utf8"
                );
    
                // コネクターを作成
                var mysql = new MySqlConnection(connectionParams);
    
                try
                {
                    // 接続開始
                    mysql.Open();
                }
                catch (MySqlException ex)
                {
                    // 何らかの理由で接続に失敗した
                    Console.WriteLine(ex);
                    throw ex;
                }
    
                // サンプルではこういうテーブルにアクセスしている
                // CREATE TABLE shoplineup(ID INT AUTO_INCREMENT NOT NULL PRIMARY KEY, Name VARCHAR(16) NOT NULL, Price INT NOT NULL);
    
                // コマンド文字列用変数
                string cmd = "";
    
                // insertしてみる
                cmd = @"INSERT INTO shoplineup SET Name='Sword', Price=100;";
    
                // コマンドコンポーネント作成
                var insertCmd = new MySqlCommand(cmd, mysql);
    
                // 実行
                MySqlDataReader insertResult = insertCmd.ExecuteReader();
    
                // 変更を与えた件数を表示してみる
                Console.WriteLine("{0}row affected", insertResult.RecordsAffected);
    
                // 結果を閉じる
                insertResult.Close();
    
                // selectしてみる
                cmd = @"SELECT * FROM shoplineup;";
    
                
    
                // コマンドコンポーネント作成
                var selectCmd = new MySqlCommand(cmd, mysql);
    
                // 実行
                MySqlDataReader selectResult = selectCmd.ExecuteReader();
    
                // MySqlDataReaderというクラスに結果が入っている
                // Read()を呼ぶことで次の行にアクセスする
    
                while(selectResult.Read())
                {
                    var id = selectResult.GetInt32("ID");  // フィールド名でのアクセス
                    var name = selectResult.GetString(1);  // カラムインデックスでのアクセス
                    var price = selectResult.GetUInt32(2); // 同上
    
                    Console.WriteLine("ID:{0} Name:{1} Price:{2}", id, name, price);
                }
    
                // 結果を閉じる
                selectResult.Close();
    
                // Mysql接続終了
                mysql.Close();
            }
        }
    }
    

    今回はサンプルとして、sample_dbというデータベースにあるshoplineupテーブルに対してinsertおよびselectをする例を作ってみました。

  5. DataTableで欲しい場合

    var datatable = new DataTable();
    var adapter = new MySqlDataAdapter(query, mysql);
    adapter.Fill(datatable);
    return datatable;

    このようにして、クエリを実行する部分にMySqlDataAdapterを使用することで結果をDataTableで得ることも出来ます。

  6. こんなことに使えます
    MySQLターミナルクライアントを作ることも出来ますし、機能をテンプレート化してデータの集計用クライアントとしても使うことが出来ます。

まとめ

SSH接続及びMySQL接続をC#でやってみるというチャレンジでしたが、いかがでしたでしょうか?
パッケージのおかげで誰でも簡単に実装出来るので、アイディア次第ではとても便利なアプリを作ることが出来ると思います。
C#でSSH接続やMySQL接続をやってみたいという方のお役に立てれば幸いです。