条件
- TCPを使用してファイルを相手に送る
- UDP に置き換えても使用できるようにしたい
普通に読み込んで書き込み
FileTransfer v1.0 で使用した方式
ファイルを一定バイト読み込んでストリームの書き込み送信の繰り返し。
- 場合によってはファイルデータが変わってしまう。
UDP に置き換えた際データを確実に送れない。
ピースに分けて送信
本題はこれ。
ファイルデータを複数のピースに分けて送信する方式。
まず1ピースのデータは
とする。
全体のバイト数を X として、ハンドシェイク時に渡せばそれで完結する。
UDP に置き換えてもピースにナンバーがあるから大体どこらへんに来るデータかわかる。
暗号化する際や、SHA256データを必要とする際も1ピース毎に行えるからかなり効率的なはず。
そして最後のピースで余りが出ても1ピース毎にサイズを指定してあるから問題ない。
public class Piece { private const int HEADER_SIZE = 8; // Long to byte private const int PIECE_N_SIZE = 4; // Int to byte private int number = 0; // Piece Number private int size = 1024; // piece size private int writed = 0; // real byte private byte[] buffer; public Piece(int number, int size) { this.number = number; this.size = size; this.buffer = new byte[size]; } public int Number { get { return number; } } public int Size { get { return size; } } public int Writed { get { return writed; } } public void Write(byte[] buf) { Array.Copy(buf, 0, buffer, 0, buf.Length); writed = buf.Length; } public void Read(byte[] buf) { Array.Copy(buffer, 0, buf, 0, buf.Length); } public byte[] toBuffer() { int bufferedSize = piece.Size + HEADER_SIZE; if (piece.Size > size) { throw new ArgumentOutOfRangeException("Size to large"); } byte[] buf = new byte[piece.Size]; byte[] buffer = new byte[bufferedSize]; byte[] header1 = BitConverter.GetBytes(piece.Number); byte[] header2 = BitConverter.GetBytes(piece.Writed); // or piece.Size piece.Read(buf); Array.Copy(header1, 0, buffer, 0, PIECE_N_SIZE); Array.Copy(header2, 0, buffer, PIECE_N_SIZE, PIECE_N_SIZE); Array.Copy(buf, 0, buffer, HEADER_SIZE, buf.Length); //int offset = HEADER_SIZE + buf.Length; return buffer; } }