条件
- 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;
}
}