現在,参考書にしたがってC++でソケットプログラミングを書いています.
sendとrecvを非同期にするために,本では select関数やWSAAsyncSelect関数などを利用していて,実際,本のとおりに書いて上手く動いています.
ここで伺いたいのですが,recvは,どうやって「データが届いたか」を知るのでしょうか.
同期ならば,トランシーバでの会話のように送信側が「どうぞ」といって送受信を交代させることができますが,非同期ならばそれができません.
NICとかが,プログラムに「届いたぞ!( or これから届くぞ!)」と教えてくれるのでしょうか.あるいは逆に,プログラムがNICに「届いてる?」と聞いているのでしょうか.仮に,ここに書いたような方法で届いたことが分かったとしても,どれくらい受け取ればいいかは分かりません(それも併せて教えてもらっているのでしょうか.データを送るときには,どれだけ送ればいいか分かりますよね.受信するときはどうしてるのかを知りたいと思っています).
No.1ベストアンサー
- 回答日時:
Linux しか知らないので Linux で説明をします。
NIC が通信パケットを受け取ると割り込みが発生し、CPU は割り込みを受け付けて、対応するデバイスドライバを起動します。この時、ドライバはソケットバッファと呼ばれる構造体にパケットの中身をコピーして、Linux カーネルの本体に渡し、そこで TCP 等の上位プロトコル処理が行われます。
一方、ユーザプログラムの方は、 select() なり read() で待っている訳ですが、OS はもちろんプロセスが何を待っているかを知っているので、対応する待ちの条件が満たされると、この場合は select() や read() が、抜けてくる(return する)訳です。
という事で、ユーザのプログラムは select() なり read() なりで受信データを「待つ」ことが必要です。もちろん select() や read() が呼ばれた時点で既に受信しているのならば、それらは直ぐに帰ってきます。read() や recv() はデータが届いた事を知る、というよりは、届いているかチェックして、まだ届いていなければ届くまで待つ(read() が抜けてこない)という処理になります。また NIC とユーザプログラムが直接やり取りをするのではなく、間にバッファがあって、対応するソケットのデータがある(受信済み)/ないか(未受信)、という問い合わせを行っているだけです。
ソケットの場合、データの送受信は非同期であり、送受信のタイミングのずれは(ソケット)バッファである程度吸収されます。もちろん、送受信バッファが満杯になった場合は流量制御が働いて、結果的に送信側の write() や send() が待ちに入ることになります。
Linux (Unix) のソケットの受信では、read() 等で指定されたバッファが常に満杯で返されるとは限らない設計になっています。つまり、その時に受信しているデータを返すだけなので、read() で返されたバイト数を必ず見ないと間違った動きになるので注意してください。
No.2
- 回答日時:
recv自身には、「データが届いた」か知る機能はありません。
何をするのかと言いますと、「届いているデータをバッファから取り出す」ことしかできません。
もしメッセージが届いていなかった場合には、「届くまで待つ」状態になります。(ブロッキングモード)
また、届いていなかった場合には即座にエラーとなることもあります。(ノンブロッキングモード)
では、どうやって届いたのかを知るのかと言いますと、サンプルにあったselectなどで、「データが届いているのか?」をバッファに対して問い合わせているのです。
NICは受信したデータを内部のバッファへと格納します。
Select関数により内部バッファにデータがあるのかを確認します。
recv関数により内部バッファからユーザのバッファへデータを転送します。
(ブロッキングモードの場合には、recvが内部バッファにデータが格納されるまで待ちます)
次にどれだけのデータを受信すればいいのかですが…
適当な量のバッファを用意して、recvに入れてもらうことになります。
ただし、recvでは「実際にバッファに入れることができたデータサイズ」を返します。実際に通信で取得できたデータサイズとは異なります。
例えば、recvで10kのバッファを用意して10kのデータを受信しようとしても、2k、4k、2kと受信が行われる場合もありえます。
この場合には、3回recvを呼び出さないといけないことになります。
どれだけのデータを通信するのかは、あらかじめ決めておくか(HTTPなどでは、ヘッダ中にデータの長さが書いてあるなど)、データがなくなる(コネクションを切断する)まで受信するという風に決めておく必要があります。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
ゆるやかでぃべーと すべての高校生はアルバイトをするべきだ。
高校生はアルバイトするべきだろうか?賛成だったら「賛」、否定だったら「否」を文頭においてあなたの意見を教えてください。
-
フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
あなたが普段思っている「これまだ誰も言ってなかったけど共感されるだろうな」というあるあるを教えてください
-
映画のエンドロール観る派?観ない派?
映画が終わった後、すぐに席を立って帰る方もちらほら見かけます。皆さんはエンドロールの最後まで観ていきますか?
-
海外旅行から帰ってきたら、まず何を食べる?
帰国して1番食べたくなるもの、食べたくなるだろうなと思うもの、皆さんはありますか?
-
天使と悪魔選手権
悪魔がこんなささやきをしていたら、天使のあなたはなんと言って止めますか?
-
ソケットのrecvの戻り値が0
C言語・C++・C#
-
Winsockで接続待ちタイムアウトを設定する方法
C言語・C++・C#
-
recv関数の受信結果について
C言語・C++・C#
-
-
4
UDP通信におけるbind関数について
C言語・C++・C#
-
5
recv関数でフリーズしてしまう
C言語・C++・C#
-
6
recv関数の戻り値について
C言語・C++・C#
-
7
TCP/IP のパケットの分断と結合について
UNIX・Linux
-
8
ネットワーク切断を検出するには?
C言語・C++・C#
-
9
TCPのプログラミングで質問…というか確認しておきたいことが…
C言語・C++・C#
-
10
Socket通信の0バイト受信について
Java
-
11
C言語で、メモリを解放しないで終わるプログラム
C言語・C++・C#
-
12
WinsockAPIのrecvfromの受信データがおかしい
Visual Basic(VBA)
-
13
DWORDの実際の型は何でしょうか
C言語・C++・C#
-
14
UDP受信時の通信異常検知について
C言語・C++・C#
-
15
ソケットのクローズについて
C言語・C++・C#
-
16
構造体のメンバをfor文で回したい
C言語・C++・C#
-
17
winsock recvでデータの取得方法
C言語・C++・C#
-
18
CFileDialogの最初のディレクトリ設定
C言語・C++・C#
-
19
意味不明の実行時エラーで困っています
その他(プログラミング・Web制作)
-
20
パケット受信 recvfrom( )について
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C# シリアル通信でデータ受信...
-
Linuxでのシリアル通信について...
-
WriteFile()でのデータ送信がで...
-
winsockの動作について。
-
VB2010 シリアル受信した情報を...
-
VB2005でWin32APIを用いてRS-23...
-
WaitForMultipleObjects関数の...
-
winsockでソケット通信の開発を...
-
ネットワークカメラの動画保存...
-
Macターミナルで実行中のプログ...
-
バックグラウンドのプロセスの...
-
VBAの配列サイズとメモリに関して
-
VBAで外部プログラムを非表示で...
-
アセンブラのタイマー割り込み
-
C++でシェルを起動
-
プロセスIDの取得方法について
-
sendkeysにてALT+CTRL+INSERTを...
-
ヘッダファイル? malloc.hと...
-
分を時間に変換するプログラム
-
Windows上で、シグナル(SIGTERM...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C# シリアル通信でデータ受信...
-
WriteFile()でのデータ送信がで...
-
winsockでソケット通信の開発を...
-
socket: recvはいつ,どれだけ...
-
シリアル通信の出力バッファと...
-
「スイッチングハブのバッファ...
-
SocketのSend関数でのCLOSEの検...
-
Connection reset by peer
-
WaitForMultipleObjects関数の...
-
RS232C通信(PC⇔PLC)
-
VB2005でWin32APIを用いてRS-23...
-
Linuxでのシリアル通信について...
-
UDP処理のエラーについて
-
シリアルポート通信
-
ソケット通信内 read関数について
-
TCP/IP通信プログラミングにお...
-
rs232cでの受信データ(mscomm)...
-
write関数でEAGAINのエラー発生...
-
シリアル通信ができません
-
【CAsyncSocket::OnReceive()呼...
おすすめ情報