01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
2009-08-27 Thu
■ マルチスレッド [D言語]
気がついたら std.thread から core.thread になってた。
ThreadGroup て言う機能が増えていた。
複数のスレッドをグループ化して扱うもの。
サンプルを書いてみた。
クロージャも一緒に使ってみる。
import core.thread; import std.stdio; auto func(string name,long w) { return (){ for(int i = 0;i < 10;i++) { writefln("%s = %d",name,i); Thread.sleep( w ); } }; } void main() { ThreadGroup tg = new ThreadGroup; tg.create(func("foo",10_000_000)); //1秒毎にカウント すぐに実行 tg.add(new Thread(func("bar",5_000_000))); //0.5秒毎にカウント tg.add(new Thread(func("baz",5_000_000))); //0.5秒毎にカウント writeln("thread start"); foreach(t;tg) { if(!t.isRunning) t.start;//未実行のスレッドを起動 } writeln("thread all join"); tg.joinAll; //すべてのスレッドの終了を待つ writeln("thread end"); }
2009-08-21 Fri
■ chunk をデコード [D言語]
手抜き
byte[] decodeChunked(byte[] src) { byte[] d; size_t spos,epos,cpos,chunkSize; int i; while(1) { cpos = (cast(string)src[spos..$]).indexOf("\r\n") + 2; //チャンクサイズが書いてある行を取得 epos = spos + cpos; if(src.length < epos) break; chunkSize = strtol((cast(string)src[spos..epos]).ptr,null,16); //チャンクサイズを取得 d ~= src[epos..epos+chunkSize]; //チャンクサイズ分追加 spos = epos+chunkSize+2; if(src.length < spos) break; } return d; }
strtol のエラー処理
chunk extension
trailer
の処理が抜けている。
2009-08-13 Thu
■ HTTP クライアントを書いた [D言語]
HTTP/0.9 用のクライアントを書いた。
サイトによってはレスポンスヘッダが帰ってくる。
次は、1.0を実装してみよう。
private import std.socket; private import std.string; private import std.regex; private import std.conv; struct URI { string scheme; string host; string port; string path; string query; string fragment; this(string uri) { auto r = regex(r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?","g"); foreach (m; match(uri, r)) { if(m.pmatch[2].startIdx != -1) scheme = m.input[m.pmatch[2].startIdx .. m.pmatch[2].endIdx]; if(m.pmatch[4].startIdx != -1) { int len = m.input[m.pmatch[4].startIdx .. m.pmatch[4].endIdx].indexOf(":"); if(len != -1) { host = m.input[m.pmatch[4].startIdx .. m.pmatch[4].startIdx + len]; port = m.input[m.pmatch[4].startIdx + len + 1 .. m.pmatch[4].endIdx]; }else{ host = m.input[m.pmatch[4].startIdx .. m.pmatch[4].endIdx]; } } if(m.pmatch[5].startIdx != -1) path = m.input[m.pmatch[5].startIdx .. m.pmatch[5].endIdx]; if(m.pmatch[7].startIdx != -1) query = m.input[m.pmatch[7].startIdx .. m.pmatch[7].endIdx]; if(m.pmatch[9].startIdx != -1) fragment = m.input[m.pmatch[9].startIdx .. m.pmatch[9].endIdx]; } } const string toString() { string s; if(scheme) s ~= scheme ~ ":"; if(host) s ~= "//" ~ host; if(port) s ~= ":" ~ port; if(path) { s ~= path; }else{ s ~= "/"; } if(query) s ~= "?" ~ query; if(fragment) s ~= "#" ~ fragment; return s; } } class HttpClient { private: TcpSocket socket; string httpVersion; public: this(string httpVersion) { switch(httpVersion) { case "HTTP/0.9": this.httpVersion = httpVersion; break; default: new Exception("HTTPVersion not supported"); } } byte[] get(in string uri) { switch(httpVersion) { case "HTTP/0.9": URI u = URI(uri); ushort port = 80; if(u.port) port = to!(ushort)(u.port); auto ia = new InternetAddress(u.host,port); socket = new TcpSocket(ia); string req = "GET " ~ u.path ~ "\r\n"; socket.send(req); int read; byte[] recv; byte[1024] buf; while((read = socket.receive(buf)) > 0) { recv ~= buf[0 .. read]; } return recv; default: new Exception("HTTPVersion not supported"); } } byte[] get(in string uri,in string proxy) { switch(httpVersion) { case "HTTP/0.9": URI u = URI(uri); URI p = URI(proxy); if(p.port) port = to!(ushort)(p.port); auto ia = new InternetAddress(p.host,port); socket = new TcpSocket(ia); string req = "GET " ~ u.toString ~ "\r\n"; int sent; sent = socket.send(req); if(sent == -1) { throw new Exception("error socket send"); } int read; byte[] recv; byte[1024] buf; while((read = socket.receive(buf)) > 0) { recv ~= buf[0 .. read]; } if(read == -1) { throw new Exception("error socket recive"); } return recv; default: new Exception("HTTPVersion not supported"); } } }
使い方
auto client = new HttpClient("HTTP/0.9"); byte[] recv = client.get("http://example.com/"); write(cast(char[])recv);
2009-08-12 Wed
2009-08-10 Mon
■ std.regex の captures が残念な動作をする [D言語]
Captures captures();
括弧で指定したサブマッチの情報を、
ランダムアクセスレンジとして取得します。
第一要素はマッチ全体を表します。Example: foreach (m; match("abracadabra", "(.)a(.)")) { foreach (c; m.captures) write(c, ';'); writeln(); } // writes: // rac;r;c; // dab;d;b;
rfc3986 の付録 B. 正規表現による URI 参照の解析を使うと、
string uri = "http://www.ics.uci.edu/pub/ietf/uri/#Related"; auto r = r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?"; foreach (m; match(uri, r)) { int i = 0; foreach (c; m.captures) { writefln("$%d = %s",i++,c); } }
こんな風に書いたら、
$0 = http://www.ics.uci.edu/pub/ietf/uri/#Related $1 = http: $2 = http $3 = //www.ics.uci.edu $4 = www.ics.uci.edu $5 = /pub/ietf/uri/ core.exception.RangeError@std.regex(1667): Range violation
std.regex を見たら、
captures は サブマッチがすべてマッチしているのを前提にしているようだ。
Captures 構造体の front 関数の定義
Range front() { return input[matches[0].startIdx .. matches[0].endIdx];// startIdx endIdx が -1 になる可能性がある。 }
マッチしていないサブマッチも出力するなら、
captures でなく pmatch を使って書く必要がある。
string uri = "http://www.ics.uci.edu/pub/ietf/uri/#Related"; auto r = r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?"; foreach (m; match(uri, r)) { foreach (i,c; m.pmatch) { if(c.startIdx != -1) { writefln("$%d = %s",i,m.input[c.startIdx..c.endIdx]); }else{ writefln("$%d = <undefined>",i); } } }
出力結果
$0 = http://www.ics.uci.edu/pub/ietf/uri/#Related $1 = http: $2 = http $3 = //www.ics.uci.edu $4 = www.ics.uci.edu $5 = /pub/ietf/uri/ $6 = <undefined> $7 = <undefined> $8 = #Related $9 = Related
captures はマッチしたものだけを返すなら、
Captures 構造体の front 関数の定義はこうか?
Range front() { if(matches[0].startIdx == -1) popFront; return input[matches[0].startIdx .. matches[0].endIdx]; }
Captures 構造体の length 関数の定義はこうか?
size_t length() { size_t count foreach (m;matches) { if(m.startIdx != -1) count++; } return count; }