• ベストアンサー

ソケットで通信するデータの帯域制御方法

ソケットでデータをやり取りするプログラムを、C言語で組んだのですが、今はとりあえず100バイトずつ送受信しています。 これを、指定された帯域を越えない範囲で、できるだけたくさんデータを送るようにしたいと考え、トラフィックシェーピングを実装したいのですが、どのようにすればいいのか、実装方法がわかりません。 (今はただ文字データをやり取りしているだけなのですが、これをファイル転送ができるものにしたいため。) どんなものでもいいので、参考になるサイトやサンプルソース等を定時いただければと思います。

  • SSMSE
  • お礼率25% (17/67)

質問者が選んだベストアンサー

  • ベストアンサー
  • jjk65536
  • ベストアンサー率59% (66/111)
回答No.1

先日速度制限しながら送信するプログラムを仕事で書いたので、 ソース貼れませんがロジックだけ返答してみます。 (x)bpsで(y)byte送信するのにかかる時間は(z)秒とします。 1.現在時刻取得 2.send()でyバイト送信 3.現在時刻を取得し、1.の値を引いて送信所要時間を算出 4.sleep(z-3.の値) 5.1へ 上記のような送信ループを実装しました。 実際には0.??秒になるのでsleep()ではなくusleep()を呼びました。 送信後、余った時間は寝てもらうというわけです。 質問者様の環境が書かれていないのでアレですが、 私はLinuxで実装したので、現在時刻の取得には gettimeofday()を使いました。 蓄積誤差が発生するので、なるべく分解度の高い時刻やsleepを 使うといいと思います。 # たとえばtime()は秒を返すのでこういうケースでは使えません 若干でも参考になれば幸いです。

SSMSE
質問者

補足

有難うございました。ロジックだけでも助かります。 ちなみに、私はWindows環境で作成しています。 なにか注意事項や補足がありましたら、よろしくお願いいたします。 あと、「2.send()でyバイト送信」とありますが、これはサイズの大きなファイルでも(分割などはせず)とりあえず一気に送って、送信にかかる時間(何十秒とか何分とか)だけ待つ、ということでしょうか?

その他の回答 (3)

  • jjk65536
  • ベストアンサー率59% (66/111)
回答No.4

> よろしければ、もう少し説明していただけないでしょうか? では、実際に計算してみると分かるでしょうか。 前出の計算式を使って、10Mずつ送信するケースを考えると、 1Mbpsに制限したい場合、10Mbyte(10000000byte)送信するのに必要な時間は x = 1000000(bps) y = 10000000(byte) z = 10000000 * 8 / 1000000 = 80(秒) となります。 実際には10Mbyteを10秒で送信してしまった場合、70秒待てば 実質1Mbps相当ですよね、長い目でみれば。 しかしながら、最初の1秒間に注目してみると、全力で送信してますので 1Mbpsになったとは言えません。 1000byteずつ送信とsleepをくりかえした場合、最初の1秒に注目しても だいたい1Mbps程度となります。 小刻みに送ったり休んだりしてるので。 通信速度計りながら実際にやってみると分かりますよ。 > これは、fflush()が「コールした瞬間、バッファのパケットが発射される」ように(私が)実装すれば、という認識で正しいでしょうか? > それとも、fflush()が「コールした瞬間、バッファのパケットが発射される」ように実装されていれば、でしょうか? 曖昧な表現になってしまってすみません。 後者が正解です。 Posixではバッファをクリアする関数が用意されてるので、それを使ってみるのが正解かな、と 思ったもので。 参考までにfflush()のmanを貼っておきますね。 > fflush - ストリームの内容を強制的に出力(フラッシュ)する > > 書式 > #include <stdio.h> > > int fflush(FILE *stream); > > 説明 > fflush() 関数は、ユーザー空間でバッファリングされているすべてのデータを > 与えられた出力に書き出す (フラッシュする)。あるいはストリーム stream の > 下 位にある書き込み関数を用いてこのストリームを更新する。ストリームは開 > いた状態のままであり、この関数によって何の影響も受けない。 >

SSMSE
質問者

お礼

締め切ってポイントを付けるのが遅くなって申し訳ありません。 最後まで丁寧にご説明いただき、本当に有難うございました。

SSMSE
質問者

補足

有難うございました。 >実際には10Mbyteを10秒で送信してしまった場合、70秒待てば >実質1Mbps相当ですよね、長い目でみれば。 >しかしながら、最初の1秒間に注目してみると、全力で送信してますので >1Mbpsになったとは言えません。 平均1Mbpsだからといって、実際の送信状態が一定になっているとは限らない、ということですね。

  • jjk65536
  • ベストアンサー率59% (66/111)
回答No.3

> ところで、「1000byteに深い意味はないですが、・・・」とのことですが、この値はどのように決めたらよいのでしょう? > 一般的にこのくらいの値を使うことが多い、とか、こういう計算で求める、とか、帯域に対して何%、とか、あるのでしょうか? きっと質問されると思ってました(^^; これは正直私も論理的にどうっていうものはありません。 一つの考え方として、一般的にパケットサイズは1500byteです。 TCPヘッダを除くと1460byteですので、それより小さめがいいかなと 考えることができます。 ただし、send()時すぐに送信されるのか、バッファリングして適当なタイミングで まとめて送信するのかなどがネットワークスタック(TCP/IPドライバ)の実装次第で変わります。 ようはsend()一発とパケット1つが対応する保証がないので、 上のように考えても意味がないとも言えます。 実際に動作させる環境で様子をみて、期待と違う動きをしていたら 「この辺の仕様が思ってるのと違うのかな?」と思いを馳せつつ 送信サイズをチューンするって感じですかね。 Posix関数にはfflush()というバッファをクリアする関数があって、 これをコールした瞬間、バッファのパケットが発射される実装のものも あります。 一般的な数値も私は分からないです。 ただ、例えば10Mbyteごとにsleep()では、送信の時間と待ち時間が それぞれ長くなりすぎて、ネットワーク負荷が矩形波のように なってしまうことは想像できるかと思います。 そうならなさそうな数値ってことで、パケットサイズよりちょっと小さい 1000くらいとしてみました。 1460送ってfflush()が正解かもしれませんね。 割と適当でも動いてしまったので、それ以上私は調べてないというのが 本音のところです。 すみません。

SSMSE
質問者

補足

何度もお答えいただき、本当に有難うございます。 いくら探しても、これぞという値の決め方が見つからなかった理由がちょっとわかった気がします。 ですが、まだちょっとよくわからないところがあります。 よろしければ、もう少しお付き合いください。 >ただ、例えば10Mbyteごとにsleep()では、送信の時間と待ち時間が >それぞれ長くなりすぎて、ネットワーク負荷が矩形波のように >なってしまうことは想像できるかと思います。 すみませんが、ここがちょっとわかりません。よろしければ、もう少し説明していただけないでしょうか? (一気に大きなサイズを送り出したら、送信中は帯域を占有してしまうであろうことまではわかるのですが・・・) 不勉強で申しわけありません。 >1460送ってfflush()が正解かもしれませんね。 これは、fflush()が「コールした瞬間、バッファのパケットが発射される」ように(私が)実装すれば、という認識で正しいでしょうか? それとも、fflush()が「コールした瞬間、バッファのパケットが発射される」ように実装されていれば、でしょうか? こちらも不勉強で申しわけありません。

  • jjk65536
  • ベストアンサー率59% (66/111)
回答No.2

1です。 > とりあえず一気に送って、送信にかかる時間(何十秒とか何分とか)だけ待つ、ということでしょうか? それだとbps的にばらつきが出ますので、1000byte程度ずつ 送ります。 (1000byteに深い意味はないですが、小さめということで) たとえば1Mbpsに制限したい場合、1000byte送信するのに必要な時間は x = 1000000(bps) y = 1000(byte) z = 1000 * 8 / 1000000 = 0.008(秒) となりますので、0.008秒で送信したいわけです。 ここで、たとえば送信が0.005秒で終わってしまった場合、 0.003秒のsleep()で調整してやると、転送レートが だいたい1Mbpsとなります。 コレをファイル転送が終わるまでループで処理すると、 指定速度でファイルが転送されていきます。 Windowsでの注意点ですが、確かWin32APIのSleep()はあんまり 分解能が高くないので(参考URL参照)、送信サイズをもう少し 大きくするなどの工夫がいると思います。 過去実験した個人的な数値では、50ミリ秒以下のSleep()は 全て50ミリ秒待たされてしまいました。Windows2000での実験だったと 思うので、XPやVistaでどうなってるかは分りません。 作ってみたけど妙に通信速度が遅い、といったときには この辺を疑ってみてください。

参考URL:
http://oshiete1.goo.ne.jp/qa1796385.html
SSMSE
質問者

補足

有難うございました。 やり方は、一度にドカッと、ではなく、一定量(少量)を送り続ける、なのですね。 ところで、「1000byteに深い意味はないですが、・・・」とのことですが、この値はどのように決めたらよいのでしょう? 一般的にこのくらいの値を使うことが多い、とか、こういう計算で求める、とか、帯域に対して何%、とか、あるのでしょうか? たびたびですみませんが、よろしかったらご教授願います。

関連するQ&A

  • VB6で画像ファイルのソケット通信

    VB6で画像ファイルのソケット通信をしなければいけなくて、 サンプルソースを探しているのですが、どなたか すごくシンプルでもよいので教えて頂けないでしょうか。 javaやCなどのサンプルは見つかるのですがVB6しか分からなくて 困ってます。文字列のやりとりのサンプルはありましたが、 画像ファイル(JPEGとかTIFとか)をやり取りするときの バイナリ(?)で送って、受取ってというところのサンプルが ほしいのです。。どなたか助けてください。

  • VB.NETでソケット通信を実装しようとしています。

    VB.NETでソケット通信を実装しようとしています。 実装しようとするのは送信側です。 カンマ区切りのパラメータを送り、 受信側から戻りパラメータとしてカンマ区切りのデータを受け取るものです。 以下を参考としているのですが、 特にパラメータの設定の部分 カンマ区切りのデータをどこで設定すべきかわからない状況です。 http://dobon.net/vb/dotnet/internet/downloadusesocket.html サンプルソース等でご指摘いただけるとうれしいです。 初心者です。申し訳ございません。 ご回答お願いします。

  • VBのソケット通信(winsock)のサイト

    VBでwinsockコントロールを使ってソケット通信にて、データの送受信をするプログラミングをするのですが、サンプルコードなどが載っているサイト、わかりやすく説明してあるサイトがありましたら教えてください。

  • c# ソケット非同期通信プログラム

    C#でソケット非同期通信プログラムを作りたいと思い勉強しております。ちなみにソケット通信はc言語ではやっておりました。 今作りたいと思ってるプログラム ・ラジオボタンで接続形態(サーバー・クライアント)を選択。 ・送信ボタンを押した時は送信 ・受信した時は受信データをテキストボックスに表示 ・コネクション数は1つで送受信を行う お手数ではございますが、参考になる様なサイトやアドバイス等があれば宜しくお願い致します。

  • ソケット通信時のエンディアン変換について

    現在、WindowsとLinux(Unix)でソケット通信を行い、データをやり取りするプログラムを作成しています。 ソースコードやコンパイルの環境は、 Windows側(Windows7):C言語(Windowsプログラミング)、VisualStudio2013でビルド&実行 Linux側:C++、g++(Cygwinを使用) 送信したいデータは、 Windows→Linuxはfloat型の配列に保持しているデータ Linux→Windowsはconst string型のデータ です。 (1)例として、送りたいfloatのデータが float a[3]; a[0] = 1.1; a[1]=2.2; a[2]=3.3 であるとします。(実際には負の値も考えられます) floatは4バイトなので、各要素でエンディアンを変えてa[0]からa[3]のデータを一括してLinux側にsendしたいと考えているのですが、どのように実装すればよいかが分かりません。 for(int i=0; i<3; i++){ //htonl(*(long*)&a[i]);でエンディアンを変換 //変換したものを何かしらの変数に保存 } //保存しておいたものをsend という大まかな流れだけは考えているのですが、実際どう実装していけばいいのか分からず困っています。 (2)(1)のデータを受信した側で元のfloatのデータに直す方法 (3)Linux→Windowsではstring型のデータを送りたいのですが、c_strを用いてchar型に変換したものをそのままsendしてよいのでしょうか? (char型は1バイトなのでエンディアンを変換する操作は必要はないでしょうか?) もし分かることがありましたら、教えていただけると助かります。 よろしくお願いします。

  • 制御 通信 組みこみプログラム

    今までずっとwindows上で動くアプリの開発をしてきました。 制御、通信、組み込み系のプログラムにも興味が出てきて試しに作ってみたいと思います。 例えばPCと他のハードウェアと通信を行い、データのやり取りをする といったプログラムを作ってみたいのですが、初心者でもわかるようなサンプルプログラム もとい、サイトないでしょうか?

  • ページ制御

    いつも参考にさせて頂いています。 現在下記開発環境にてアプリを開発中です。 ・struts 1.2 ・eclipse 3.0 ・JDK 1.4.12 ・tomcat 5.0 ・mysql 4.01 selectして取得したデータ数によってページ遷移(「前へ」「次へ」みたいな感じでしょうか)を実装したいと思ってますが、どのように実装すればいいのかわかりません。 oracleではROWNUMとか使ったりして実装していたのを見たことはあるのような気がするのですが、アルゴリズム的な根本的なことがわかってないので詰まっている状態です。 そこでお聞きしたいのですが、例えば120件データを取得した場合、1ページに15件まで取得して次のページにはまた15件…というふうにページを遷移する実装はどうしたらできるのでしょうか?サンプルソースなどありましたらとても助かります。 どうか宜しくお願いします。

  • TCPによるファイル転送

    質問です。よろしくお願いします。 いま、winsockでクライアントからサーバにバイナリファイルを転送するプログラムを組んでいます。内容は、サーバ側を待機の状態にし、クライアントからの要求があった時点で新たにソケットを作ってそこからデータのやり取りをするというものです。 しかし、ソケットを使った通信がサーバからクライアントの一方通行になってしまっていて、データを送ることが出来ません。(クライアントから送ったデータは0になっているようにも思われます) ソケットは一方通行なのでしょうか?参考にしている本のサンプルではお互いにやり取りをしていたと思うので、そのようなことはないと思うのですが・・・。 内容分かりにくければご質問ください。 回答お待ちしています。

  • Linux+GCCで、ソケットプログラム

    お世話になっております。 Linux<-->Win間で、データ送受信するプログラムを作りたいと思っています。 現在は、Win<-->Win間でWinSockを使ったプログラムがほぼ完成していますが、次の方向性としてLinux<-->Win間ソケットプログラムなのです。将来的には、組み込みPCとしてつかいたいのです。 DOSの頃(8年前くらい)にC言語はやっていたので、C言語は多少は覚えていますが、Linuxを使った事が無い、GCCの経験が無いので、OSの選択やGCC(特にソケット)に関する勉強をしなければなりません。 そこで、こういったジャンルを勉強できる本を探しているのですが、皆さんのお勧めは無いでしょうか?

  • COMポートに流れるデータを監視する方法について

    ComPortキャプチャのような COMポート(シリアルポート)を経由してやりとりされる送受信データをキャプチャするツールを作成しようとしております。 言語は、C言語でBCCdeveloperの環境で 作成しております。 WIN32APIの下記の関数でなんとか 送受信できるツールは、できました。 CreateFile GetCommState ClearCommError WriteFile ReadFile ひとつのツールでポートをオープンすると 別のソフトからはオープンできないようなので、 なんとかして、他のソフトが送受信しているデータを キャプチャできる方法ありましたらご教授願います。

専門家に質問してみよう