Techracho

TcpListenerを使ったTCPサーバ

このエントリーをはてなブックマーク Share
2009.01.26    C#, Web, Windows, ネットワーク, 馬場   タグ: , —    baba   

C#のTcpListenerを使って、サーバを作っていています。

System.Net.Sockets.Socket.Available プロパティは、信用してはいけません。
下のコードは、クライアントから接続があってもたまにしか受信できません。

using (Socket client = listener.AcceptSocket())
{
  //ここにThread.Sleep(1000)とかを入れるとうまく動くことも多い・・・

  while (client.Available) //ここでいきなりfalseが返ってくる
  {
    byte[] buf = new byte[256];
    client.Receive(buf);
    Console.WriteLine(Encoding.ASCII.GetString(buf));
  }
}

この場合、次のようにするのが正しいです。

using (Socket client = listener.AcceptSocket())
{
  byte[] buf = new byte[256];
  int bytes;
  while ((bytes = client.Receive(buf)) > 0)
  {
    Console.WriteLine(Encoding.ASCII.GetString(buf));
  }
}

それから、TcpListenerのコンストラクタは第一引数にローカルIPアドレス、第二引数にポート番号を渡しますが、サーバに置いては
TcpListener listener = new TcpListener(IPAddress.Any, 45678);
のように IPAddress.Any を渡すのが正しいです。「ローカルIPアドレス」といっても、サーバマシンのアドレスでは無く、クライアントのアドレスを渡します。わかりにくい。。

127.0.1.1

このエントリーをはてなブックマーク Share
    Linux, 中井      hiko   

FTPの設定をしている時にはまったのですが、下記のようなログがでてうまくいかなかったので何なのかと思って調べてみると、

Ubuntu(Debian)のバグ?というか/etc/hostsに勝手に書かれた設定の影響みたいです。

> Jan 17 12:34:50 xxxx proftpd[18744] xxxx.xxxxx.xxx: 127.0.1.1:21 masquerading as
127.0.1.1
(あるのかわかりませんが)意図があるのだとしても、これによって動かなくなるソフトウェアはあるようなので、

ネットワーク周りを扱うソフトウェアでかつDebian系列で、はまった時は/etc/hostsの設定を見直してみることをお勧めします。

<参考>

http://itmst.blog71.fc2.com/blog-entry-100.html

オーバーライドでちょっとはまりました

このエントリーをはてなブックマーク Share
2009.01.22    C#, 馬場   タグ: , , , , , —    baba   

C#で System.Xml.XmlDocument を使っています。
XmlDocument xmlDocument = new XmlDocument();

プレフィックス付きのノードを作るとき、たとえば


<s:root xmlns:s="urn:hogehoge-hoge" >
    <s:child />
</s:root>

というXMLを作りたいとして、

XmlNode root = xmlDocument.CreateNode(XmlNodeType.Element, "s", "root", "hogehoge-hoge");
XmlNode child = xmlDocument.CreateNode(XmlNodeType.Element, "s", "child", "hogehoge-hoge");
root.AppendChild(child);

とすると動きますが、毎回NamespaceURIを指定するのは変だと思います。
しかし、最後の引数を指定しないと、prefixが出力されません。

また、
xmlDocument.Save("filename");
でファイルに保存するのは1行ですが、string型で受け取ろうと思うと、

StringWriter writer = new StringWriter();
xmlDocument.Save(writer);
string output = writer.ToString();

としないといけません。

色々不便なので、XmlDocumentを継承したExtendedXmlDocumentを作りました。命名がSXGA並にださいですが。。
このクラス内部では、prefixとnamespaceURIのHashtableを持っていて、一度指定すると以降はnamespaceURIを指定しなくても対応するものを用意してくれます。
また、ToString() をオーバーライドしてあるので、1行で文字列を受け取れます。

・・・と、ここまでは良かったんですが(前置きが長い)、
その後調子に乗ってCreateAttribute()をオーバーライドしたらはまりました。

public override XmlAttribute CreateAttribute(string prefix, string name, string value);
を作って、内部で
base.CreateAttribute(name);
を呼ぶと、StackOverflowExceptionが発生します。

どうやら、XmlDocument.CreateAttribute(string) 内部で CreateAttribute(string, string, string) を呼んでいたみたいです。
C#のオーバーライドは動的にメソッドを呼んでくれるので、派生クラスのCreateAttribute(string, string, string) が呼ばれてしまって、その内部で CreateAttribute(string) を呼ぶと無限ループ、と。

.NET Frameworkの内部コードが見られれば一瞬で解決した問題なんですが。
オーバーライドは慎重に使わないとバグの元ですね。オーバーロードと組み合わさるとたまに危険。気をつけます。

CakePHPのfind, findAll, findCount, delete, deleteAll

このエントリーをはてなブックマーク Share
2009.01.21    CakePHP, PHP, 伊藤   タグ: , , —    tomotaka   

追記: 馬場が記事にしてくれたCakePHP findの形式も非常に参考になります!

伊藤です。

開発ブログには初投稿です。
よろしくお願いします。

今回は最近話題のCakePHPでモデル(データベーステーブル)からデータを取り出したり、カウントしたりするためのfind, およびfindCountの使い方をまとめてみたいと思います。
そんなの本でもWebにでもどこでも載ってるよ!と言われるかもしれませんが、実際に使ってみて1.1に沿ったの内容の解説が多かったり、内容が不正確であったりと困惑したためCakePHP1.2で実際に動くコードということで改めてまとめてみたいと思います。
また、データを削除する際に便利なdeleteやdeleteAllについても触れてみます。
本稿で想定しているCakePHPのバージョンは1.2です。
最近1.2の安定版も出ましたので、これからCakePHPの開発というと1.2が主流になってくるのではないかと思います。

findおよびfindAll
データベースからデータを取得するにはモデルオブジェクトのfindメソッドやfindAllメソッドを使うのがCakePHPの一般的なやり方です。
findAllは以下のようにして使います。タイプ数が少なくて便利なのですが、今後find(”all”, …)形式の呼び出しに統一されやがてfindAllという名前のメソッドはなくなる予定だそうです。

findAllの使い方:

// 取得するフィールドや取り出す並び順が決まっている場合
function someaction() {
    $condition = array("hoge" => 1);
    $fields = array("id", "hoge", "hogege", "moge", "mogege");
    $order = "moge";
    $records = $this->Model->findAll($condition, $fields, $order);
}

// 並び順デフォルト、取得するフィールド全ての場合
function someaction2() {
    $condition = array("hoge" => 1);
    $records = $this->Model->findAll($condition);
}

findで条件に合致する最初の1件のレコードを取得する:

// 取得するフィールドや取り出す並び順が決まっている場合
function someaction() {
    $condition = array("hoge" => 1);
    $fields = array("id", "hoge", "hogege", "moge", "mogege");
    $order = "moge";
    $record = $this->Model->find(
        "first",
        array("conditions" => $condition, "fields" => $fields, "order" => $order)
    );
}

// 並び順デフォルト、取得するフィールド全ての場合
function someaction2() {
	$condition = array("hoge" => 1);
	$record = $this->Model->find("first", array("conditions" => $condition));

	// $record= $this->Model->findByHoge(1);
	// という書き方もできます
}

findで条件に合致する全てのレコードを取得する:

// 取得するフィールドや取り出す並び順が決まっている場合
function someaction() {
    $condition = array("hoge" => 1);
    $fields = array("id", "hoge", "hogege", "moge", "mogege");
    $order = "moge";
    $records = $this->Model->find(
        "all",
        array("conditions" => $condition, "field" => $fields, "order" => $order)
    );
}

// 並び順デフォルト、取得するフィールド全ての場合
function someaction2() {
	$condition = array("hoge" => 1);
	$records = $this->Model->find("all", array("conditions" => $condition));
}

findByIdでフィールド’idが特定の値の1件のレコードを取得する:

function someaction() {
	$record = $this->Model->findById(1); // idが1のレコードを取り出す
}

帰ってくるデータ:

// findAllやfind("all", ...)で帰ってくる形式(複数レコード)
array(
	[0] => array(
		"ModelName" => array(
			"field1" => "value1",
			"field2" => "value2"
		)
	),
	[1] => array(
		"ModelName" => array(
			"field1" => "value1",
			"field2" => "value2"
		)
	),
	...
)

// findByXxxやfind("first", ...)で帰ってくる形式(単一レコード
array(
	"ModelName" => array(
		"field1" => "value1",
		"field2" => "value2"
	)
)

findCountで条件にマッチする行数を数える:

function someaction() {
	$condition = array("year" => 2009);
	$count = $this->Model->findCount($condition);
	// array("conditions" => $conditition)のような形式のオプション配列ではない,
	// findAllに与えるようなarray("field" => "value")形式の配列でよい
}

findAllやfind(”all”, …)で取り出してcount()してもいいのですが、マッチする件数が多い場合はメモリを食いつぶしてしまいますので、
RDBMSに数えてもらうようにするのがスマートな実装でしょう。

deleteメソッドやdeleteAllメソッドでレコードを削除する

// deleteメソッド: 単一のレコードをIDで指定して削除
function someaction() {
	$deleteTargetID = 1;
	if ($this->Model->delete($deleteTargetID)) {
		// 成功
	} else {
		// 失敗
	}
}

// deleteAllメソッド: 条件にマッチする複数のレコードを一括して削除する
function someaction2() {
	$deleteCondition = array("year" => 2009);
	if ($this->Model->deleteAll($deleteCondition)) {
		// 成功
	} else {
		// 失敗
	}
}

deleteメソッドもdeleteAllメソッドも成功すると真を返します。
ちなみにdeleteAllにarray(”conditions” => $condition)のようなfindのオプション形式の配列を渡すと必ず真が帰ってくるので気を付けましょう!

CakePHPはまだ日本語のドキュメントも不十分でWeb上にも1.1と1.2の情報が完全に整理されないまま混在しているため、
開発も手探り感が強いですが基礎の部分をしっかり理解して使いこなせば役に立つツールのひとつだと思います。
今後もCakePHPに関する情報を掲載していきたいと思いますのでよろしくお願いします。
コメントやトラックバックでのツッコミも歓迎致します!

参考:

今年の投資

このエントリーをはてなブックマーク Share
    渡辺   タグ: , , , —    peter   

2008年は、環境に投資しました。

様々な方から感謝しきれないほどの好意と力添えに支えられ
BPSも2008年にはいってようやく会社として最低限の基盤ができ、
仕事を管理できる人員も増え、結果誇れるお仕事も増えてきました。

2009年は、人に投資する年にしたいと考えています。

環境も人も会社のパフォーマンス・ケーパビリティを大きく左右します。
スティーブン・コヴィーが語るようにどちらも投資とメンテナンスによって
成長する会社の宝ですが、今年は人に重きを置きたいと思います。

手始めに
システム開発会社として不可欠であるマガジンへの購読を始めました。

他にもいろいろありそうなので、他社さんから勉強させてもらって、

実施していきたいですね。

匿名メソッドで別スレッドからControlを操作するときのメモ

このエントリーをはてなブックマーク Share
2009.01.17    C#, Windows, 馬場      baba   

C#でWindows Formアプリ作成のメモ。

メインスレッド以外からFormのコントロールを変更しようとすると、InvalidOperationException が発生してしまいます。
例外を押さえ込んでも解決にはならないので、この場合は System.Windows.Forms.Control の BeginInvoke() を使えば良いみたいです。

この BeginInvoke() には Delegate を渡すのですが、どうせ1回しか使わないので匿名メソッドで済ませたいところ。
普通にやると「匿名メソッドからDelegateにキャストできません」と言われるので、MethodInvoker 型にキャストしてやると良いようです。


//別スレッド
void OtherThreadFunction()
{
//textBox1.Text = "ほげ"; これは例外が出る

textBox1.BeginInvoke(
(MethodInvoker)delegate(){textBox1.Text="ほげ";}
);
}

C#な人には常識なのかもしれませんが、便利だなあと感心しました。
今やっているプロジェクトは移植性を考慮に入れる必要があるため、本当は高度な言語仕様に依存したコードは増やしたくなかったんですが、便利なので使うことにします。

参考
http://www.atmarkit.co.jp/fdotnet/dotnettips/660anonymethod/anonymethod.html

Windows 7 その2

このエントリーをはてなブックマーク Share
2009.01.12    Windows, 馬場   タグ: —    baba   

Windows 7から書き込みです。
なぜかWindows 7上のIE8だとWordPressの管理画面が使えなかったので、Firefoxから。
VistaのIE8なら大丈夫だったのに。。。

Windows 7ではアクセシビリティが向上していました。

  • DPI変更後再起動しないでもログオフ・ログオンでOK
  • 拡大鏡が大幅に進化、Macの拡大機能みたいになった
  • スクリーンキーボードがかっこよくて使いやすくなった

などなど。

アクセシビリティ向上に努める姿勢は良いですね。見習っていこうと思います。

Windows 7 public beta

このエントリーをはてなブックマーク Share
2009.01.11    Windows, 仮想化, 馬場   タグ: —    baba   

Windows 7のベータ版が、ようやくダウンロード出来るようになったので、早速Virtual PCに入れてみました。
(本当は9日公開予定だったのが、アクセス集中で延期したみたいです)

インストーラはほとんどVistaと同じで、起動後は全体的にVistaを洗練された感じです。仮想マシンなのでパフォーマンスの評価は出来ませんが、普通に使えそうです。
電卓がパワーアップしたのが一番のポイントかも。

以下、インストール~起動までのスクリーンショットを載せておきます。

jQuery

このエントリーをはてなブックマーク Share
2009.01.06    Web, javascript, 中井      hiko   

遅ればせながらJQuery触ってみました。

思ったより楽なので、早く使えばよかったと若干後悔しました。

ちなみに若干はまったポイントをメモしておきます。

IDセレクタでID名に.や/なんかが入っている場合、エスケープしないといけないのに気づかず、少々はまりました。

きっと、エスケープしなきゃいけない宗教の人による設計なんでしょう。

prototype.jsではエスケープしなくてもよかったのに。ぶつぶつ。

とはいえ、リファレンスちゃんと読んだら書いてありましたが^^;

$(”#hoge[1]“).html(); ×

$(”#hoge\\[1\\]“).html(); 〇

<参考>

http://semooh.jp/jquery/api/selectors/id/

ネットワークエラーの解決

このエントリーをはてなブックマーク Share
2009.01.02    Linux, ネットワーク, 仮想化, 馬場   タグ: , , —    baba   

仮想サーバのNICに負荷をかけるとホストマシンごと落ちる件について、現状改善したように見えるので、解決記録を書いておきます。

まず蟹が原因と思い、ヨドバシカメラにNICを買いに行きました。新春セールでポイント5%アップで幸せ気分です。
本当はIntelが欲しかったけど売ってなかったので、玄人指向のGBE-PCIe(Marvell 88E8053)とGbE-PCI2(VIA VT6122)を買ってきました。PCIeが良いのでMarvellの方を使うつもりで、VIAは予備用に買いました。

早速Marvellに差し替えたところ、負荷をかけてもホストOSは落ちなくなりました。やっぱり蟹が原因だったみたいです。
(ちなみに、NICのMACアドレスが変わった場合、Ubuntuの場合 /etc/udev/rules.d/70-persistent-net.rules を編集すれば eth0 に割り当てるなど出来ます)
しかし、ホストOSは落ちないものの仮想サーバの通信は負荷をかけるとやっぱり切れてしまいます。
調べてみると、eth0: out-of-sync dirty pointer というエラーを出していました。また、ifconfigをみるとエラーがたくさんあります。

そこで、使っていたBUFFALO製のスイッチングHUBを外して、仮想サーバ用のMarvellとRTX1000を直接つないでみたら、負荷をかけてもエラーが出なくなりました。
スイッチングHUBをcorega製に変えてみても、エラーは出ませんでした。

つまり、RealtekのNICとBAFFALOのHUBが両方悪かったみたいです。
値段だけで選ぶと痛い目に遭いますね。

古い投稿 »

COPYRIGHT [C] 2009 BEYOND PERSPECTIVE SOLUTIONS LTD. ALL RIGHTS RESERVED.