Techracho

XAMPPでRailsのProxy

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

Railsで開発する際は、素直にRadRailsのボタンでサーバを起動してしまうのが楽で良いです。
例:http://localhost:3000

しかし、ポート番号ではなく好きな名前でアクセスしたいこともあります。
また、Rails 2.3には、prefix(ドメイン直下以外にアプリを配置)にバグがあるため、それをローカルで試したいこともあるかもしれません。

XAMPPだけで普段はサーバ作業に触れない人には馴染みが薄いかもしれませんが、Apacheなので、たんなるProxyならかんたんです。
例:http://localhost/myapp

<VirtualHost *:80>
	ProxyRequests Off
	<Proxy *>
		Order deny,allow
		Allow from all
	</Proxy>
	ProxyPass /myapp http://localhost:3000
	ProxyPassReverse /myapp http://localhost:3000
</VirtualHost>

なお、肝心のPrefixバグの対策は、システムチームの伊藤がブログを書いていますのでご覧下さい。
http://www.bpsinc.jp/blog/archives/1579

Twitterウィジェットで日本語検索対応

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

TwitterをWebページに埋め込むのに、簡単なのは公式ウィジェットを使うことです。

これを使えば、特定のキーワードにマッチするつぶやきをリアルタイムで取得できます。
http://twitter.com/goodies/widget_search

ところが、ここのプレビュー画面だと日本語検索に対応していますが、出力されたコードを設置すると、日本語キーワードを使った場合にエラーが出てしまいます。

例:「子育て」で検索した際のエラー
syntax error
http://search.twitter.com/search.json?q=-RT%20%u5B50%u80B2%u3066&callback=TWTR.Widget.receiveCallback_1&rpp=30&clientsource=TWITTERINC_WIDGET
Line 1

見て分かるとおり、URLエンコードの形式が変になっていますね。

この場合、読み込むwidget.jsをプレビュー画面と同じものに切り替えてあげれば動きました。

<!-- これなら日本語OK -->
<script src="http://twitter.com/javascripts/widgets/widget.js"></script> 

<!-- このコードが生成されるが、これは日本語不可 -->
<script src="http://widgets.twimg.com/j/2/widget.js"></script>

非公式なので、変わるかもしれませんが・・・

URL.openConnection()でFileNotFoundException

このエントリーをはてなブックマーク Share
2010.05.20    android, ネットワーク, 馬場      baba   

Androidで、URLを指定してInputStreamを受け取りたいとき、

URL url = new URL("http://example.com");
InputStream is = url.openConnection().getInputStream();

とできますが、なぜかAndroid 2.1では動き、1.6ではFileNotFoundExceptionが発生しました。

原因究明したいところですが、とりあえずHttpClientに置き換えれば動きます・・・

HttpClient client = new DefaultHttpClient();
HttpGet method = new HttpGet(URI.create("http://example.com"));
HttpResponse response = client.execute(method);
InputStream is = response.getEntity().getContent();

DNSのサフィックス設定

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

ActiveDirectoryを使う環境では、DNSサーバがSRVレコードをサポートしている必要があります。
(通常のDNSだとDomainControllerを検索する際にエラーになってしまいます)

BINDなどのDNSサーバで設定することも可能ですが、かなり面倒なので、Windows ServerをプライマリDNSにしてしまうのが手っ取り早いですね。

ところが、Windows ServerをプライマリDNSにしているActiveDirectory環境で、LANから公開サーバを検索しようとしたら、少しだけ困ったことになりました。
公開サーバ(WAN/LANの2つのIPを持つ)の名前をwwwとすると、

DNSサーバ:192.168.1.50
公開サーバ:192.168.1.10 , 203.143.124.180

期待する結果

C:> nslookup www.bpsinc.jp
サーバー: UnKnown
Address: 192.168.1.50

名前: www.bpsinc.jp
Address: 192.168.1.10

残念な結果

C:> nslookup www.bpsinc.jp
サーバー: UnKnown
Address: 192.168.1.50

名前: www.bpsinc.jp.bpsinc.jp
Address: 203.143.124.180

このように、bpsinc.jpのサフィックスが無駄にくっついてしまいます。

これは、ネットワーク設定→TCP/IP(IPv4)設定→詳細設定→DNS で、以下のようにDNSサフィックスを手動設定すれば直ります。

ローカルでここを変更してもOK

ローカルでここを変更してもOK

グループポリシーで一括設定するには、コンピュータの構成→ポリシー→管理用テンプレート→ネットワーク→DNSクライアント→DNSサフィックス検索一覧 で設定すればOKです。

グループポリシーでDNSサフィックス設定

グループポリシーでDNSサフィックス設定

もちろん、www.bpsinc.jp. のように最後にピリオドをつければ何もしなくてもOKなのですが、
WindowsのFQDN判定はあまり賢くないということでしょうか?

C#でUDPパケットをひたすら送り続ける

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

先日のiPhone UDP受信テストの際に使った、WindowsからUDPパケットを送りつけるプログラムを載せてみます。
一切の遠慮無く、1秒に20枚のペースで、デスクトップに置いてあるimg0.png~img9.pngの画像ファイルを一方的に送りつけます。

///一定時間ごとにUDPで画像を一方的に送りつける
private void SendData()
{
    //ローカルポート番号2222にバインドする
    System.Net.Sockets.UdpClient udp = new System.Net.Sockets.UdpClient(2222);

    int count = 0; //何番目の画像を送信するかのカウンタ

    Timer timer = new Timer();
    timer.Tick += new EventHandler((s, e) =>
    {
	    if (++count > 9)
	    {
	        count = 0;
	    }

	    //デスクトップのimg0.png~img9.pngを送る
	    string filename = @"C:\Users\baba\desktop\img\" + count + ".png";
	    using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read))
	    {
	        byte[] sendBytes = new byte[fs.Length];
	        fs.Read(sendBytes, 0, sendBytes.Length);
	        //宛先IPとポート番号を指定する
	        udp.Send(sendBytes, sendBytes.Length, "192.168.100.50", 5555);
	    }
    });
    timer.Interval = 50;
    timer.Start();
}

.NETは簡単にこういったコードが書けて便利ですね。
何の工夫も最適化も無いですが、50枚/秒くらいなら全然問題にならない程度の速度は出ていました。

iPhone用 超手抜きUDPサーバ

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

先日のiPhone性能検証で作ったソースの一部として、超手抜きUDPサーバのコードを載せておきます。
CFSocketが思ったよりも使いにくいので、BSDソケットほとんど生です・・・

/**
 * 手抜きUDPサーバ
 */
#import <netinet/in.h>
#import <Foundation/Foundation.h>

@interface MyUdpConnection : NSObject {
	id delegate;
}
- (id)initWithDelegate:(id)_delegate; //receiveData:(NSData*)data を実装すること
- (void)bind;
- (void)bindThread;
@end

/**
 * 手抜きUDPサーバ実装部
 */
@implementation MyUdpConnection

// 初期化
- (id)initWithDelegate:(id)_delegate {
	delegate = _delegate;
	return self;
}

// 受信開始
- (void)bind {
	NSThread *th = [[NSThread alloc]initWithTarget:self selector:@selector(bindThread) object:nil];
	[th start];
}

// 受信用スレッド
- (void)bindThread {
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];

	struct sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	addr.sin_port = htons(5555); //適当なポートで待機
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);

	int sock = socket(AF_INET, SOCK_DGRAM, 0);
	bind(sock, (struct sockaddr *)&addr, sizeof(addr));

	char buf[100000]; //100KBまで対応
	while (1) {
		//ここでデータを受信するまでブロックされる
		int size = recv(sock, buf, sizeof(buf), 0);

		//NSDataに変換し、delegateに通知
		NSData *data = [NSData dataWithBytes:buf length:size];
		[delegate performSelectorOnMainThread:@selector(receiveData:) withObject:data waitUntilDone:YES];
	}

	[pool drain];
}
@end

これを使うと、たとえばViewControllerなどで

- (void)receiveData:(NSData *)data;

を実装しておいて、

MyUdpConnection *udp = [[MyUdpConnection alloc]initWithDelegate:self];
[udp bind];

のようにすれば、データを受信したときにreceiveData:が呼ばれます。

エラー処理や再送処理はおろか、ポート番号すらべた書きのものですが、重要でないデータを受け取る分には、ちょっと改良すれば使い物になりそうです。

iPhoneのNSURLConnection性能限界テスト

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

iPhoneやiPod Touchは、ネットワークの性能がそれほど高くないため、NSURLConnectionでたくさんコネクションを張ったりすると目に見えて遅延します。
以下のような実験をやってみました。

iPhone SDKで、以下の2種類のテストアプリを作りました。
なお、機材の都合上iPhoneではなくiPod Touchを使っています。

【A】
タイマーで0.05秒ごとにHTTPリクエストを送信し、レスポンスとして受け取った画像を表示する。
サーバでは、リクエストを受け取るたびに0~9の数字画像を順番に返す。

【B】
UDPで接続を待ち、画像データを受け取ったら表示する。
サーバでは、iPhoneに向かって0.05秒ごとに0~9の数字画像を順番にUDPで送信する。

サーバは、十分に高性能なマシンを、有線LANで接続しました。
MacBook ProやiPod Touch実機は、同じ無線LAN (IEEE802.11g) を使っています。

【結果】
Aのアプリ(MacBook Pro上のシミュレータ)
Aのアプリ(iPod Touch 実機)
Bのアプリ(iPod Touch実機)

このように、HTTPを使う場合、シミュレータではスムーズに動くものの、実機ではかなりカクカクです。
実機でも、HTTPを使わずにUDPにしてしまえば、十分スムーズになることが分かります。

今回使った画像は各2KB程度のPNG画像ですが、50KB程度のJPG画像を使っても結果はほとんど変わらなかったため、帯域よりもコネクションの数が大きなウェイトを占めているようです。

どの程度性能が出るか大まかに分かれば良かったので、原因などの細かい検証は今回は行いません。
使ったソースコードなどは後日このブログに載せておこうかと思います。

iPhoneでXMLRPC

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

iPhoneでXML_RPCを使おうとすると、地味に苦労します。

XMLParserはあるので、自力でやっても良いのですが、出来ればライブラリが欲しいですよね。

eczarny xmlrpcがiPhone対応ということですが、私の環境ではターゲットをiPhone OSにするとビルドエラーが出ました。
MacOSをターゲットにすると正常にビルドできます。NSXMLDocumentなどを内部で利用しており、これがiPhone非対応なのが原因みたいです。2.0~2.2.1まで全滅でした。

ということで他を当たったところ、WordPress for iPhoneの内部で使われているものが良さそうでした。
これもeczarmy xmlrpcをベースに作られているようですが(未確認)、iPhoneでもちゃんと動きます。

ということで、以下からソースコードをダウンロードします。ライセンスはGNU GPLでした。
http://iphone.trac.wordpress.org/browser(trunkを開いて、下の方にあるZip Archiveをクリック)

色々入っていますが、Classes/XMLRPCフォルダ丸ごとと、Classes以下でファイル名に「+」が含まれるものを全部コピーして、プロジェクトにインポートすればOKです。

このようにインポートします

このようにインポートします

使い方は、以下のようにやります。

#import "XMLRPCRequest"
#import "XMLRPCResponse"
#import "XMLRPCConnection"

- (void)test {
	//requestを生成
	NSURL *url = [NSURL URLWithString:@"http://www.bpsinc.jp"];
	XMLRPCRequest *request = [[XMLRPCRequest alloc]initWithHost:url];
	[request setMethod:@"Test.version" withObjects:[NSArray array]]; //引数を指定するときはarrayの部分にデータを入れる

	NSLog(@"%@", [request source]); //XMLRPCのリクエストソースが見られます

	//通信
	XMLRPCResponse *response = [XMLRPCConnection sendSynchronousXMLRPCRequest: request];

	NSLog(@"%@", [response source]); //XMLRPCのレスポンスソースが見られます
	NSLog(@"%@", [response object]); //objectメソッドは、戻り値の型になります。サーバ側で明示的に型を指定しましょう
}

ソースコードは短く読みやすいので、簡単に使いこなせると思います。
非同期通信は、以下の2つを実装すれば、XMLRPCConnectionのinitWithRequestで実行できます。

- (void)connection:(XMLRPCConnection *)connection
  didReceiveResponse:(XMLRPCResponse *)response forMethod:(NSString *)method;
- (void)connection:(XMLRPCConnection *)connection
  didFailWithError:(NSError *)error forMethod:(NSString *)method;

PEAR::XML_RPC2で簡単サーバ

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

XML_RPCのクライアントを開発するとき、ダミーでサーバが必要になります。
手っ取り早いダミーとして、PHPのPEAR::XML_RPC2が便利です。以前クライアント側は紹介しましたが、今回はサーバの超基本的な使い方。

ダウンロード
http://pear.php.net/package/XML_RPC2からダウンロードできます。

使い方
適当な場所に設置したら、以下のようにincludeして、各アクションに対応する関数を定義します。
そして、XML_RPC_Serverでアクション名と実行するアクションの対応を配列で渡せばOKです。

require_once("XML/RPC.php");
require_once("XML/RPC/Server.php");
$GLOBALS['XML_RPC_defencoding'] = "UTF-8";

function  version($params) {
	return new XML_RPC_Response(new XML_RPC_Value('1.0', 'string'));
}

function average($params) {
	$v1 = $params->getParam(0)->scalarval();
	$v2 = $params->getParam(1)->scalarval();
	return new XML_RPC_Response(new XML_RPC_Value($v1 + $v2, 'int'));
}

new XML_RPC_Server(array(
	"Test.version" => array("function" => "version"),
	"Test.average" => array("function" => "average"),
));

とってもかんたん。

NSURLRequestでsetHTTPBodyするとtimeoutIntervalが上書きされる

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

先日に引き続き、timeoutIntervalが無視される件について。

POSTする際は、NSMutableURLRequestを用いて、setHttpBodyでPOSTデータを入れます。
しかし、これを行うとtimeoutIntervalが強制的に240秒に設定されてしまいます。
さらに酷いことに、その後setTimeoutIntervalを行っても無視されます。

以下検証コード↓

NSURL *url = [NSURL URLWithString:@"http://www.bpsinc.jp"];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
NSLog(@"%g", [req timeoutInterval]); //60

[req setHTTPBody:[NSData data]];
NSLog(@"%g", [req timeoutInterval]); //240

[req setTimeoutInterval:10.0];
NSLog(@"%g", [req timeoutInterval]); //240

これはCocoaのバグでしょうか?

あまりに酷すぎるので、何か基本的な間違いを犯していると信じたいところです。
どなたか情報をお持ちなら教えて下さい!

1月14日追記
詳しい方から、「仕様です」との情報を頂きました。
非同期通信を使って、タイムアウトは自分で処理する必要があるそうです・・・

古い投稿 »

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