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

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

新規登録して質問してみよう
ただいま回答率
85.37%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

TCP

TCP(Transmission Control Protocol)とは、トランスポート層のプロトコルで、コネクション型のデータサービスです。

UDP

UDP(User Datagram Protocol)とは、トランスポート層のプロトコルであり、コネクション型のデータサービスです。IPネットワーク上の別のホストにコンピュータのアプリケーションがメッセージを送ることができ、転送チャンネルやデータ経路を設定する必要はありません。TCPに比べて高速であるが、信頼性が薄いという特徴があります。

Q&A

解決済

3回答

16208閲覧

C# UdpClient 分割送信方法

sem2012sp_a

総合スコア49

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

TCP

TCP(Transmission Control Protocol)とは、トランスポート層のプロトコルで、コネクション型のデータサービスです。

UDP

UDP(User Datagram Protocol)とは、トランスポート層のプロトコルであり、コネクション型のデータサービスです。IPネットワーク上の別のホストにコンピュータのアプリケーションがメッセージを送ることができ、転送チャンネルやデータ経路を設定する必要はありません。TCPに比べて高速であるが、信頼性が薄いという特徴があります。

0グッド

1クリップ

投稿2016/04/20 09:06

編集2016/04/20 10:20

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

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

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

C#

1udp.Client.SendBufferSize = 300000;

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

<追記>

C#

1 int size = sendBytes.Length; 2 int size2 = 0; 3 byte[] data = new byte[16000]; 4 while (size > 16000) 5 { 6 Array.Copy(sendBytes, size2, data, 0, 8000); 7 8 udp.Send(data, data.Length); 9 10 size2 += 8001; 11 size -= 8000; 12 13 } 14 15 Array.Copy(sendBytes, size2, data, 0, sendBytes.Length); 16 17 udp.Send(data, data.Length);

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tkanda

2016/04/20 10:47

300KBのデータは外部ファイルから読み込んだものですか?それともオンメモリで生成されたものですか? それと、0.5秒ごとに送信しているデータは、すべて欠かせない仕様ですか?それとも、いくらか抜け落ちても(相手に届かなくても)かまわない性質のものですか?
sem2012sp_a

2016/04/20 10:51

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

回答3

0

ベストアンサー

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

###送信コード修正案

C#

1byte[] data = new byte[1024]; 2int rest = sendBytes.Length; 3while (rest > 0) 4{ 5 int size = Math.Min(rest, 1024); 6 Array.Copy(sendBytes, sendBytes.Length - rest, data, 0, size); 7 udp.Send(data, size); 8 rest -= size; 9}

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

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

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

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

投稿2016/04/21 02:38

tkanda

総合スコア2425

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sem2012sp_a

2016/04/25 01:34 編集

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

0

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

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

(全データイメージ)
AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH

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

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

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

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

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

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

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

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

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

投稿2016/04/20 10:32

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sem2012sp_a

2016/04/20 10:38

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

退会済みユーザー

2016/04/20 10:55

はい,元ネタの方も拝見していました. なんでTCP送信で途中で挫折してしまうかは別の観点で追求する必要がありますが,とりあえず, ・TCPでも小さいサイズなら行ける ・大きいサイズになると挫折してしまう ・UDPだと荷物の管理もさることながら,郵便事故の対処も必要 だったら, ・分割ロジックは上記参照 ・実際の通信はUDPじゃなくてTCPでやってみたら? というお話です.イメージ湧きますかね?
sem2012sp_a

2016/04/20 10:59

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

0

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

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

投稿2016/04/20 10:08

KoichiSugiyama

総合スコア3041

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sem2012sp_a

2016/04/20 10:12

回答ありがとうございます。 >分割したければ独自の分割手順を送信側・受信側に実装するしかないのではないかと思います。 仰る通りです。 とりあえず初心者なもので、どのように分割させればいいのかわからないので、分割する方法だけでも教えていただき、受信はそれを参考に書いてみようかと思っています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問