FTPサーバへのログインが遅い

C#でNAS(LinkStation)のFTPにアクセスしまくるソフトを作るのにTKFP.DLLを使ってみることにした。接続が切れたのを検知できないので、毎回ログインする方法を取ったのだけど、ログインするごとに10秒間待たされる。毎回一定時間待たされるので、多分何らかのタイムアウトが発生しているのだろうと考えた。

  1. IPアドレスで指定するとDNS逆引きが発生してタイムアウト。: バグ。ありえないことじゃない。[FIX] WebRequest クラスを使用して Web 要求を行う際の接続の問題
  2. LinkStationはProFTPdを使っていて、こいつのオプションUseReverseDNS off, IdentLookups offが設定されていないのかもしれない。: 不明。分かったところでどうしようもない。多分ログに名前を記録するためにデフォルトではONになっていると思われる。
  3. WindowsXPのファイアウォールのせい。: よくあること。なんかよく分からないネットワークがらみのことはこれを無効にすればたいてい解決。

Wiresharkでディスプレイフィルタ「tcp.port eq 21 or ftp」かけて見ていると、「220 server ready」が返って来るのが10秒かかっていた。「ftp 220 server ready slow」でぐぐってみると、てがかりとなる議論が。

ftp login very slow [Archive] - HowtoForge Forums | HowtoForge - Linux Howtos and Tutorials

どうやらファイアウォールに引っかかっているためのようだ。ためしにファイアウォールを無効にすると待たされなくなった。しかし、無効にしとくわけにもいかないので、開くポートを限定したい。Wiresharkのフィルタを外してよく見てみると、ident 113ポートへのアクセスが3回記録されていた。どうやらこれのようだ。

「ftp 113」でぐぐってみると答えにたどり着いた。

LunaTear: XP SP2でFTPが遅くなる

参考:

DisplayFilters - The Wireshark Wiki

Windows Serviceアプリケーションの開発

最初にC#に触れてから1年近くが経とうとしているが、3ヶ月ほど前から本格的なシステムの開発を始めた。そういうわけでいろいろなところでつまづきまくっている。今回はWindowsサービスアプリケーションの開発。何とか道が見えたところで、記憶にとどめておくべきことをメモしておきたい。

クリティカルな部分をサービスに切り出して、必要なときだけGUIを立ち上げればよいような構造にしている。ゼロからの開発になるので、サービス・GUI・クラスライブラリを全部1つのソリューションの中で管理している。

サービスアプリ自体の開発はいったんやり方を見つければ簡単なんだけど、そこに行き着くまでが大変だった。ウェブ上にも古いやり方しか載っていない。installutil.exeとかコマンドラインツールを使う方法は古い。普通のアプリと同じ方法でセットアッププロジェクトを作ったあと、カスタム動作を設定するだけだ。このカスタム動作の設定の仕方は次のとおり。

1. ソリューションエクスプローラから、セットアッププロジェクトを右クリック->表示->カスタム動作

2. 開いた画面で、カスタム動作アイコンを右クリック->カスタム動作の追加

3. 開いたダイアログで、アプリケーションフォルダをダブルクリック。
 

4. アプリケーションのプライマリ出力を選択してOK。

5. 2の画面の各アクションにプライマリ出力が追加される。各アクション(イベント)のコールバックはProjectInstaller.csに自動的に実装される。
 

私は、これにインストール時に起動、アンインストール時に停止するアクションを加えた。ProjectInstallerのデザイナのイベントプロパティから、AfterInstall, BeforeUninstallイベントハンドラを追加する。ソース全体は以下のようになった。

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.ServiceProcess;
using System.Windows.Forms;


namespace SignalService
{
    [RunInstaller(true)]
    public partial class ProjectInstaller : Installer
    {
        public ProjectInstaller()
        {
            InitializeComponent();
        }

        public override void Install(IDictionary stateSaver)
        {
            base.Install(stateSaver);
        }

        public override void Commit(IDictionary savedState)
        {
            base.Commit(savedState);
        }

        public override void Rollback(IDictionary savedState)
        {
            base.Rollback(savedState);
        }

        public override void Uninstall(IDictionary savedState)
        {
            base.Uninstall(savedState);
        }

        private void ProjectInstaller_AfterInstall(object sender, InstallEventArgs e)
        {
            ServiceController controller = new ServiceController(serviceInstaller1.ServiceName);
            controller.Start();
        }

        private void ProjectInstaller_BeforeUninstall(object sender, InstallEventArgs e)
        {
            ServiceController controller = new ServiceController(serviceInstaller1.ServiceName);
            try
            {
                controller.Stop();
            }
            catch (Exception)
            {
            }
        }
    }
}

過去にうちの先輩がC++で開発した、リモートデバッグ機能付きのロギングDLLを使おうとしたのだが、実はサービスアプリケーションで使うのは初めてだった。DllImportして使うわけだが、サービスが起動しているときに、GUIからもこのDLLを呼ぶと、System.DllNotFoundExceptionが発生する。サービスでなければ2つのアプリケーションから同時に使うことは問題なかったので、多分ユーザ権限の問題なのだろう。サービスはLocalSystemで動作させていた。このDLL特有の問題なのかもしれない。

また、ログファイルの出力先をカレントディレクトリのlogフォルダ(“.log”)としていたのだが、なぜかファイルが書かれない。絶対パスを指定するとちゃんと書かれるので、Program Filesに書くには特別な権限が必要なんだろうかと想像したりもしたが、デバッガをアタッチしてみると、実は単にカレントディレクトリが C:WINDOWSsystem32 になっていることが分かった。そこには普通にログが書き出されていた。以下のようにカレントディレクトリを移動することで解決した。

        private void MoveCurrentDirectory()
        {
            Assembly exe = Assembly.GetEntryAssembly();
            FileInfo exeFileInfo = new FileInfo(exe.Location);
            Directory.SetCurrentDirectory(exeFileInfo.DirectoryName);
        }

結局このDLLはサービスで使うと他で使えないようだったので、サービス用のロガーはC#で書いた。たいした機能はないが、キューイングして別スレッドで遅延書き込みみたいなことを実装した。リモートデバッグはとりあえず、Debug.Printで我慢する。

SQL Server 2008 Express Editionのインストールではまる

VS2008についてきたSQL Server 2005 Expressからアップデートした。しかし、Management Studioは2005のままだったので、なんとなく気持ち悪くてこいつも2008にしようとしたところ、なぜかはまった。

それは、インストールルールのチェックで、Visual Studio 2008 SP1を要求されるという問題だった。すでにSP1はインストールされているんだけど・・・。

これがなかなかクリアできず、結局SQL Server 2008ごとアンインストールしてインストールしなおした。

しかし、同じ問題が出る。異様に時間のかかるインストール・アンインストールに発狂しそうになりながら、待っている間いろいろ調べていると、ようやく答えにたどり着いた。

CSS SQL Server Engineers  SQL Server 2008, Visual Studio 2008 SP1, and .Net Framework 3.5 SP1 explained....

結局、以前F#のインタラクティブシェルを使ってみたくて入れた、Visual Studio 2008 Shell (integrated mode) というやつが原因だった。これをアンインストールするとすんなり進んだ。

なお、僕の環境では入っていなかったが、Visual Studio Tools for Applications 2.0というやつも削除する必要があるらしい。こちらは再頒布してる場所が見つからなかった。どうやって戻すのかは不明。

LiveSpaceのフォントがギザギザになる

IE7以上でメイリオをインストールした環境では、LiveSpaceの一部のテーマでスムージングが有効にならない不具合があるらしい。
 
 
今使っているテーマはXBoxのテーマの1つですが、この前まできれいに表示されていた気がします。
同じテーマで色違いのものでも、なぜか一方だけギザギザになるのが不可解。
スタイルを調べてもどちらも"font-family: Meiryo, sans-serif"だし。
これに気づいたのはIE8の再インストールをした後なので、もしかすると環境依存なのかもしれません。
 
LiveSpaceは数あるフリーのブログサービスの中でも、記事の領域も広く、レイアウトの完成度が最も高いです。
まだ記事ほとんど書いてないですが。
 
Windows Live WriterSyntax Highlighterプラグインを追加すると、ソースコードを載せるのが簡単そうです。
その辺考えられてるのは、他でははてなダイアリーくらいで、普通のブログだとインデントとか大変ですよね。
 
Update - 2009/5/6
ついにどのテーマでもギザギザになってしまった。もうだめだ。

WCFでエンドポイントを追加したらエラーになって起動できなかった

スクリーンキャストを見ながらWCFのデモを打ち込んでいたところ、2番目のデモでいきなり躓いた。

“System.InvalidOperationException: 構成で指定された X.509 証明書 ID を読み込めません。”

エンドポイントのIDタブには、mexのだけDns=localhostになっていたので、ためしに他のにも入力してみたらうF5で動くようになった。

 

じっさいのところ、Dnsはたぶん関係なくて、このタブで設定されるCertificateReferenceの部分が、App.configにはデフォルトで追加されないので、このタブを修正したことで追加されたらしい。

結局Dnsのlocalhostは元通り空白に戻したが、ちゃんと動いている。まあ、不要な値は追加しないということで、バグではないんだろうなあ、偶然でなきゃ絶対気づけなかったと思うけど。

Hatena タグ: ,,