質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.36%

C# UdpClient 分割送信方法

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 9,338

sem2012sp_a

score 16

C#でUdpClientを使い、0.5秒毎に300KB程のデータを送信するプログラムを作っているのですが、UDPではTCPと違い自動で分割?をしてくれないみたいです。
一回で送ろうとするとバッファが足りないとerrorが出ました。

分割して送信する方法を調べてみたのですが、このように1回で送信しているSampleしか出てきませんでした。

試しにこのようなコードを書いてみましたが効果がありませんでした。

udp.Client.SendBufferSize = 300000;

Udpでの分割送信方法を教えてください

<追記>

int size = sendBytes.Length;
                int size2 = 0;
                byte[] data = new byte[16000];
                while (size > 16000)
                {
                    Array.Copy(sendBytes, size2, data, 0, 8000);

                    udp.Send(data, data.Length);

                    size2 += 8001;
                    size -= 8000;

                }

                Array.Copy(sendBytes, size2, data, 0, sendBytes.Length);

                udp.Send(data, data.Length);

このような感じで送信コードを書いてみたのですが、分割して送られてくるByte配列を連結させる方法がわからないです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • tkanda

    2016/04/20 19:47

    300KBのデータは外部ファイルから読み込んだものですか?それともオンメモリで生成されたものですか?

    それと、0.5秒ごとに送信しているデータは、すべて欠かせない仕様ですか?それとも、いくらか抜け落ちても(相手に届かなくても)かまわない性質のものですか?

    キャンセル

  • sem2012sp_a

    2016/04/20 19:51

    300KBのデータはメモリから読み込んだものです。外部ファイルは一切使いません。
    いくらか抜け落ちても構いません。

    キャンセル

回答 3

checkベストアンサー

+2

TcpClientの質問の続きとして、いくつかアドバイスさせていただきますね。
まずは、分割送信のコード修正案を。

送信コード修正案

byte[] data = new byte[1024];
int rest = sendBytes.Length;
while (rest > 0)
{
    int size = Math.Min(rest, 1024);
    Array.Copy(sendBytes, sendBytes.Length - rest, data, 0, size);
    udp.Send(data, size);
    rest -= size;
}

TCPとの違いについて

TCPとUDPではいろいろと違いがありますが、問題となっている処理に深く関係することとして、次の違いを意識してコードを書く必要があります。

  • UDP はデータ境界が保証されている(一度のsend()/sendto()で送信したデータが相手側で一度のrecv()/recvfrom()で受信されることが保証されているという意味です。)ただし以下のポイントに注意!
  • UDP は送信したデータが届かないことがある。(データが破棄されたことが送信側/受信側のどちらのアプリケーションにもまったく通知されないことがある。欠落したデータのリカバリー処理が必要な場合、アプリケーションに実装する。)
  • UDP は送信したデータ順と受信されるデータ順が変わることがある。(送信データの順番を確認したり、入れ替わったデータ順を元の状態に復元する処理が必要な場合、アプリケーションに実装する。)

UDPの送信データ長について

UDP通信では一度に送信するデータ長は最大でも 500 バイトから 1300 バイト程度にするのが一般的です。何故なら、大きすぎるUDPデータは、IP層でのフラグメント分割を引き起こし、フラグメントが遺失し結果としてUDPデータが相手ノード側で破棄されるリスクを増大させるからです。

最後に

実現されようとしているシステムがどのようなものなのか解らないですが、データ送受信のコードの書き方をどうするかということの前に、システムとしてデータリカバリーの実装方法とデータの圧縮(本当に300KBのデータが全部必要なのかなど)、「回線品質の悪い状況」に関する動作保証範囲などについて改めて検討されるほうがよいかと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/25 10:30 編集

    分割してTCPで送信する方法を取り、無事実装できました。
    送信コード修正案がありがたかったので、ベストアンサーにさせて頂きました。

    socket通信では、文字列を送る事ぐらいしかしたことがなかったのですが、今回ファイルを連続で送ってみて、色々勉強になりました。
    例えば、送信側はそのままで、受信側だけ分割させても、かなりネットワーク使用率を抑えられたり、ファイルを送信するにあたり、Byte配列の結合処理など色々と学びが多かったです。まだまだプログラム初心者ですが、親切にアドバイス頂けて、とても助かりました。ありがとうございました!

    他の回答者の方も貴重な意見ありがとうございました。

    キャンセル

+2

TCP通信と違ってUDPの場合は全部自分で始末しなければならない,ということは理解されてると思います.
ちょっと今すぐにサンプルを提示することが出来ないのでアレですが,イメージとしては以下のようにお考えください.
1.分割するサイズは1度に送るサイズ-独自のヘッダサイズ
2.分割したデータの先頭(もしくは後ろでも結構ですが何処かに)荷物の順番を決める情報をのせる
3.受け取った側はその荷物の場所を考慮しながら配列にしまっていく
といった感じです.

たとえば,荷物が8個に分割されたとします.

(全データイメージ)
AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH

それぞれの荷物をおくる際にヘッダを付けます
受け取っている側は分割数も分からないので全体量を示すものもあったほうが良いかもしれないですね
0108AAAA (1/8の荷物)
0208BBBB
0308CCCC
  :
0808HHHH (8/8の荷物)

パケットサイズはこの際規定として決めてある,としましょうか.
受け取った側はヘッダ部分を取り除いて復元していきます.

その際,分割総数と受け取ったヘッダ情報から「受け取ってない荷物がないか」を逐次チェックします.
(UDPは郵便事故が起こることを否定していません)

とりあえず,末端のパケット,もしくは一定時間の空きを見て,受け取ってない荷物があるならそれを再送する(受信側→送信側への)リクエストを起こします.

UDPは余分なヘッダがついてないので早い,と言われますが,荷物の管理はかならず必要ですので,本来の用途としては

1回データを見逃すくらいどうってこと無いよ!

というケースで使うのが普通です.したがって今回のように荷物の健全性を保証しなくてはならない場合,ある程度自分で管理する必要がある,ということは判って頂けるかと思います.

じゃあどうすればいいか?

TCPで分割送信したら良いんじゃないですかね?という提案です.

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/20 19:38

    回答ありがとうございます

    最初はTCPで送信していました。
    しかし、回線の悪い環境だと送信が途中で止まって固まってしまいます。
    TCPは自動で分割?するみたいでこちらで分割サイズを指定することができず、回線の悪い環境だとそれに耐えられないみたいです。
    データサイズが300KB程なのでいける気もするんですけどね・・・
    回線速度が24M以上安定して出てる環境でも送信を開始してから数十秒後に送信が止まっていました。

    キャンセル

  • 2016/04/20 19:55

    はい,元ネタの方も拝見していました.
    なんでTCP送信で途中で挫折してしまうかは別の観点で追求する必要がありますが,とりあえず,
    ・TCPでも小さいサイズなら行ける
    ・大きいサイズになると挫折してしまう
    ・UDPだと荷物の管理もさることながら,郵便事故の対処も必要

    だったら,
    ・分割ロジックは上記参照
    ・実際の通信はUDPじゃなくてTCPでやってみたら?

    というお話です.イメージ湧きますかね?

    キャンセル

  • 2016/04/20 19:59

    なるほど、分割処理頑張ってみます。

    キャンセル

0

ご質問の意図を勘違いしていたらすみません。

UDP通信なので、送信側、受信側ともどちらも実装されることだと思いますが、仕様上特に手順もなく送りつける(と言ったら語弊があるかもしれませんが)ので、分割したければ独自の分割手順を送信側・受信側に実装するしかないのではないかと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/20 19:12

    回答ありがとうございます。

    >分割したければ独自の分割手順を送信側・受信側に実装するしかないのではないかと思います。

    仰る通りです。
    とりあえず初心者なもので、どのように分割させればいいのかわからないので、分割する方法だけでも教えていただき、受信はそれを参考に書いてみようかと思っています。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.36%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る