ファイルデータを確実に送信する

条件

  • 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;


}
}

FileTransfer

ファイル転送用のプログラム「FileTransfer」を制作しています・・・。

これから配布する準備とバグの修正を行っていくつもりです。

仕様

  • TCP を使用
  • 独自プロトコルを使用
  • UTF8文字コードを使用

プロトコル

*ヘッダー部
ファイルヘッダー (i)
ファイル名 (x)
ファイルサイズ (x)
*サブヘッダー部
sha256ヘッダー (i)
sha256 (x)

*ボディー
*空データ

ヘッダー部

ファイルヘッダーには  バイトサイズ を格納します。

ファイル名には UTF8エンコードされたファイル名が格納されます。

ファイルサイズには ファイルのサイズが格納されます。

サブヘッダー部

sha256ヘッダーには バイトサイズを格納します。

sha256 には sha256 エンコードしたデータを格納します。

ボディー部

バッファサイズ (1024) 読み取り書き込みます。

読み込みデータが 0 になった時点で読み込みを終了します。

読み込んだデータがバッファサイズに満たなかった場合

残りのデータを 255 で埋めます。

空データ部

255 で埋められたデータを送信します。

技術仕様

ヘッダー部、サブヘッダー部で使用するバイトサイズは可変配列を使用しているため受信側で対応する必要があります。

基本サイズが「256」なので2倍になれば「512」になります。

MemoryStream を使用し、読み込みが完了するまで読み込んだデータを一時的に保存します。

                using (MemoryStream ms = new MemoryStream())
                {
                    bool end = false;
                    while (!end)
                    {
                        // データ読み込み
                        byte[] fSize = new byte[256/* Global.BUF_HEAD_SIZE */];
                        stream.Read(header, 0, header.Length);
                        // 一時保存
                        ms.Write(header, 0, header.Length);
                        for (int i = 0; i < header.Length; i++)
                        {
                            // 終了フラグ
                            if (header[i] == byte.MaxValue)
                            {
                                // 終了する
                                // データの初めまで移動して読み込む
                                tmp = new byte[(int)ms.Length];
                                ms.Seek(0, SeekOrigin.Begin);
                                ms.Read(tmp, 0, (int)ms.Length);
                                end = true;
                                break;
                            }
                        }

                        // 必要なのが 1block であれば
                        //end = true;
                    }
                }

復元は

                int size = BitConverter.ToInt16(tmp, 0);

で行います。

 

sha256 の必要性

ネットワークを介したデータのやり取りでは必ずロスなどの問題が起きます。

データが正しく送れているか受け取れているか確認するためにもあった方がいいでしょう。

UDPのようにリアルタイム性のあるもの、なおかつ破損しても問題ないデータであれば別ですが。

MixSounder のご紹介

前提

このアプリは特定の状況下において大変便利なアプリです。

また使用するにあたりVB-Cable などの仮想オーディオデバイスが必要です。

(※なくても使用はできますが、あれば便利です。)

ダウンロード場所

Downloader にて配布しています。

https://devras.info/dl/?name=MixSounder

 

役立つ用途

例えば、

  • Lineなどの通話アプリで音声を流したいとき(PCの音声など)
  • 疑似的なミュート機能が欲しいとき
  • 仮想オーディオデバイスに音声を入力したいとき

他にも役立つ場面はあると思いますが、基本は上の3つだと思います。

 

使用方法

DiscordやLineなどのアプリからマイク設定を開き、入力デバイスに使用する仮想オーディオデバイスを選択し、

MixSounderの入力デバイスに標準入力のマイクを選択。

デスクトップ音声を無効にし、開始します。

これで仮想オーディオデバイス経由で音声を再生させることができます。

 

今後について

簡易的なボイチェン機能を追加しようと思っていたのですが、なかなかうまくいかずに保留しています。

実装できそうであれば、実装していくつもりですが期待はしないでください。