こんばんわ~
winsockのrecv()について疑問があります。
ソケットについては本見ながら勉強中なので知識不足な点があるかもしれません。
recvでデータを受信する際、指定した長さを1回で受信しきれるとは限らない。
と本に書いてあったのですが、具体的な例がその部分は載ってなくてなんとなくしかわかりません。
例えば
送信データの送信長を5と指定した場合、
あ、い、う、え、\0
か、き、く、け、\0
この2つを送信すると
受信側では
あ、い、う
え、\0、か、き、く
け、\0
と受信することもありえる。
ということなのでしょうか?
今はその様に仮定して\0を目安として受信側で送信データを復元するプログラムを書いているのですが、
それならばなぜrecv()で受信するデータの長さをわざわざ指定させるのか疑問に感じました。
1回で指定の長さを受信しきれないならば、結局受信側で送信時に指定した長さに復元しないとダメな気が・・・
それならば何故受信時に受信長を決めさせるのかよくわからなくなりました。
受信長が5のとき、最初に受信したのが受信長が4ならば次は1までしか受信せず5で区切ってくれるとか、
そーゆーことなんですか?
ちょっとした疑問なのでまったく切迫してないのですが、
なんか妙に気になるので、わかる方いましたらお答えいただけるとありがたいです。
winsockのrecv()についての疑問
Re:winsockのrecv()についての疑問
WinSock は使ったことが無いので予想ですけれども、
>それならばなぜrecv()で受信するデータの長さをわざわざ指定させるのか疑問に感じました。
指定しない場合、受信するデータのバッファのどこまで書き込んでいいのか分からなくなるからじゃないでしょうか。
受信側で一定量のバッファを用意していても、そのサイズが分からなければ、そのバッファ以上のデータを受信してしまうとバッファオーバーフローを起こしてしまいます。
>1回で指定の長さを受信しきれないならば、結局受信側で送信時に指定した長さに復元しないとダメな気が・・・
逐次処理していって読み捨ててもいいようなプログラムもある(受信したのをそのままファイルに出力して破棄、とか)ので、必ずしも受信側で全て復元する必要は無いと思います。
そういう場合、全部のデータの受信を待つのは無駄なので、そういうのを考慮した仕様を考えると recv のようになるんじゃないでしょうか。
もし全部のバッファを受け取って処理したいのであれば、全部受け取るまで待つという関数を書くのはそこまで難しくないと思うので、そういう関数を作ってもいいですね。
>それならばなぜrecv()で受信するデータの長さをわざわざ指定させるのか疑問に感じました。
指定しない場合、受信するデータのバッファのどこまで書き込んでいいのか分からなくなるからじゃないでしょうか。
受信側で一定量のバッファを用意していても、そのサイズが分からなければ、そのバッファ以上のデータを受信してしまうとバッファオーバーフローを起こしてしまいます。
>1回で指定の長さを受信しきれないならば、結局受信側で送信時に指定した長さに復元しないとダメな気が・・・
逐次処理していって読み捨ててもいいようなプログラムもある(受信したのをそのままファイルに出力して破棄、とか)ので、必ずしも受信側で全て復元する必要は無いと思います。
そういう場合、全部のデータの受信を待つのは無駄なので、そういうのを考慮した仕様を考えると recv のようになるんじゃないでしょうか。
もし全部のバッファを受け取って処理したいのであれば、全部受け取るまで待つという関数を書くのはそこまで難しくないと思うので、そういう関数を作ってもいいですね。
Re:winsockのrecv()についての疑問
TCPではデータストリームになるので送信データの区切りは
保持されないようです。なので送信データの区切り方とは
異なる形でデータがやってくることがあります。
>それならばなぜrecv()で受信するデータの長さをわざわざ指定させるのか疑問に感じました。
めるぽんさんのおっしゃるとおり、受信バッファよりたくさん受信しないようにするためだと
思われます。
>1回で指定の長さを受信しきれないならば、結局受信側で送信時に指定した長さに復元しないとダメな気が・・・
あらかじめ送ってくる予定のサイズを受信側に教えてあげて、受信側はそのサイズになるまで
受信するという方法があります。
/*追記*/
もうひとつの方法は送信データの最後に終了を意味する記号をくっつけるという方法です。
ただし、この記号は通信データに出てこない物にしないといけないです。
テキストデータならば現実的ですが、バイナリであった場合は意図せずに終了を意味する
記号が出てくる場合があるので難しいと思われます。
保持されないようです。なので送信データの区切り方とは
異なる形でデータがやってくることがあります。
>それならばなぜrecv()で受信するデータの長さをわざわざ指定させるのか疑問に感じました。
めるぽんさんのおっしゃるとおり、受信バッファよりたくさん受信しないようにするためだと
思われます。
>1回で指定の長さを受信しきれないならば、結局受信側で送信時に指定した長さに復元しないとダメな気が・・・
あらかじめ送ってくる予定のサイズを受信側に教えてあげて、受信側はそのサイズになるまで
受信するという方法があります。
/*追記*/
もうひとつの方法は送信データの最後に終了を意味する記号をくっつけるという方法です。
ただし、この記号は通信データに出てこない物にしないといけないです。
テキストデータならば現実的ですが、バイナリであった場合は意図せずに終了を意味する
記号が出てくる場合があるので難しいと思われます。

Re:winsockのrecv()についての疑問
出張があったもので返事が遅くなってしまいました。
申し訳ありません。
なるほど受信しすぎないための最大受信数の制限という意味だったのですね。
具体的な例を御二方ともあげてくださってわかりやすかったです。
recvは最低でも受信長1を受信するまでブロックするので
今はとりあえず1バイトずつ送信させているのですが、
御二方の助言を参考に復元するメソッドを実装してみます。
詳しい説明ありがとうございました。
申し訳ありません。
なるほど受信しすぎないための最大受信数の制限という意味だったのですね。
具体的な例を御二方ともあげてくださってわかりやすかったです。
recvは最低でも受信長1を受信するまでブロックするので
今はとりあえず1バイトずつ送信させているのですが、
御二方の助言を参考に復元するメソッドを実装してみます。
詳しい説明ありがとうございました。