matarilloの雑記

GitHubに公開したソフトウェアなどについて書きます。

ProtocolReaderというクラスを作りました

.NETの話です。タイトルに書かずに、本文の一番上に書きました。

通信プロトコルの実装みたいなのを自分で書くこと、たまにはありますよね。常にHTTPなりgRPCなりを使うわけではないのですから。

で、そういうプロトコル、テキストとバイナリが混じってたりするじゃないですか。

HTTPで画像をGETするときを例にすると、ヘッダー部はASCIIテキスト(\r\n区切り)で、その中にボディ部のサイズが含まれてて、ボディ部はバイナリ、って感じですよね。

f:id:matarillo:20170610032839p:plain

こういうのを自分で書くときに、BinaryReaderが使えそうかなと思うわけですが、区切り文字を探すときにちまちま1バイトずつ読むの、面倒じゃないですか。

かと言って、TextReaderみたいなクラスを使ってしまうと、これが内部でバッファリングしてたりとかするので、元のストリームからはボディ部のバイナリを読めなかったりするわけじゃないですか。

あと、プロトコルを理解せずにうかつに多くのバイトを読み取ろうとすると、データが送られてきてないので待つことになったりするじゃないですか。

そういうのが面倒なのでひとつクラスを書きました。Matarillo.IO.ProtocolReaderクラスです。

https://github.com/matarillo/ProtocolReader

Nugetにも登録してありますが、実体はクラス1個だけなので、ソースだけ流用して適当に使ってもらって構いません。(MITライセンスにしてあります。)

使い方

public async Task<byte[]> ReadToSeparatorAsync(byte[] separator)

separatorで指定したセパレーターが現れるまで現在のストリームを読み進め、セパレーター直前までのバイト列を非同期的に返します。 イメージはTextReader.ReadLineAsyncメソッドです。なのでセパレーターとして\r\nを渡したとき、返されるバイト列には\r\nは含みません。

public async Task<byte[]> ReadBytesAsync(int count)

countで指定した長さまで現在のストリームを読み進め、count長のバイト列を非同期的に返します。 イメージはBinaryReader.ReadBytesの非同期版です。

どちらのメソッドも、ストリームが閉じてしまった場合はそこまでのバイト列しか返しませんので、その点は注意です。