今回winsockを使った通信プログラムを組む事になったのですが、わからない点が多々ありましたので、どなたかご教授頂けると大変ありがたいです。


1. TCP通信において、送信側が"Hoge" "Fuga"と2回sendした際、受信側でrecvすると"Ho" "geFu" "ga"と3回受信する可能性があると認識しているのですが、これは正しいでしょうか?
(到着する順序は保証されるが、recvする際に送信側がどのようにsendしたかは考慮されない)

2. UDP通信においては、上記のような現象は起きないと認識しているのですが、これは正しいでしょうか?
(UDP通信では、2回sendすれば2回以上はrecvしない。パケットの破棄はあっても、分割はない)

3. もしUDP通信でも上記のような現象が起きる場合、到着順序の保証がされないという観点から、recvした際に"Ho" "ga" "geFu"と受信する事はあり得るのでしょうか?

4. 2が正しい前提での話です。UDP通信では、MTUを超えた場合、自動でパケットが分割されると聞きました。プログラムを組む際、これは意識しないといけないのでしょうか?
(MTUが1500Byteの場合、UDPで2000Byteをsendすると、recvで1500,500と2回受信する?)


以上の4点です。
どなたかご存知の方いらっしゃいましたら、是非ご教授ください。

このQ&Aに関連する最新のQ&A

A 回答 (2件)

1.正しい


TCPはバイトストリームを送ります。バイト順は保障しますがパケットの単位は考慮されません。
2.概ね正しい
UDPはパケットを送ります。パケットを勝手に分割したり結合したりはしません。ただし同じパケットが複数回受信されることはあるので送信回数より多く受信する可能性は排除できません。
3.ない
ただしパケット単位での到着順は保障されません。
4.動作としては意識する必要はない
途中のIPパケットは分割されても、UDPで再構成した上で受信します。再構成できない場合はパケットの一部が受信されるのではなくパケット全体が破棄され受信されません。
ただし、上記により大きなパケットは届きにくいのでほとんどの場合にUDPは小さいサイズで送ります。そういう意味では意識する必要があります。
    • good
    • 0

>受信側でrecvすると"Ho" "geFu" "ga"と3回受信する可能性があると認識しているのですが、これは正しいでしょうか?



1回で受信する場合もあります。
http://www.kt.rim.or.jp/~ksk/wskfaq-ja/articles/ …

>(到着する順序は保証されるが、recvする際に送信側がどのようにsendしたかは考慮されない)

概ね合っている…かと。
# 順序だけでなく、通信エラーがあった場合の再送処理なども保証されます。
# ドライバが処理しているのでプログラム側では判りませんが。

>(UDP通信では、2回sendすれば2回以上はrecvしない。パケットの破棄はあっても、分割はない)

分割に関しては不明(UDP使ったことないので)ですが…
同じパケットを複数回受信することもある…らしいです。

>3. もしUDP通信でも上記のような現象が起きる場合、到着順序の保証がされないという観点から、recvした際に"Ho" "ga" "geFu"と受信する事はあり得るのでしょうか?

ありえる。
と考えておいたほうがよい…かと。

>UDP通信では、MTUを超えた場合、自動でパケットが分割されると聞きました。プログラムを組む際、これは意識しないといけないのでしょうか?

意識すべし…なのかも知れませんが…。
下層でのデータフレームのサイズに関して、どこまで考慮すべきなのか…は不明です。
PPPの場合もあったりするでしょうし。

http://www.kt.rim.or.jp/~ksk/wskfaq-ja/intermedi …
とりあえず、よろしく処理してくれる…らしいです。
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qsocket: recvはいつ,どれだけ受け取るのか?

 現在,参考書にしたがってC++でソケットプログラミングを書いています.

 sendとrecvを非同期にするために,本では select関数やWSAAsyncSelect関数などを利用していて,実際,本のとおりに書いて上手く動いています.

 ここで伺いたいのですが,recvは,どうやって「データが届いたか」を知るのでしょうか.

 同期ならば,トランシーバでの会話のように送信側が「どうぞ」といって送受信を交代させることができますが,非同期ならばそれができません.

 NICとかが,プログラムに「届いたぞ!( or これから届くぞ!)」と教えてくれるのでしょうか.あるいは逆に,プログラムがNICに「届いてる?」と聞いているのでしょうか.仮に,ここに書いたような方法で届いたことが分かったとしても,どれくらい受け取ればいいかは分かりません(それも併せて教えてもらっているのでしょうか.データを送るときには,どれだけ送ればいいか分かりますよね.受信するときはどうしてるのかを知りたいと思っています).

Aベストアンサー

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() で返されたバイト数を必ず見ないと間違った動きになるので注意してください。

Linux しか知らないので Linux で説明をします。

NIC が通信パケットを受け取ると割り込みが発生し、CPU は割り込みを受け付けて、対応するデバイスドライバを起動します。この時、ドライバはソケットバッファと呼ばれる構造体にパケットの中身をコピーして、Linux カーネルの本体に渡し、そこで TCP 等の上位プロトコル処理が行われます。

一方、ユーザプログラムの方は、 select() なり read() で待っている訳ですが、OS はもちろんプロセスが何を待っているかを知っているので、対応する待ちの条件が満...続きを読む

QUDP通信する時に、相手にどうやって自分のポート番号を教える?

UDP通信する時に、相手(送信側)にどうやって自分(受信側)のポート番号を教えるのでしょうか?

例えば、下記のページのサンプルだと、受信側は5555で待ち受けていますが、この場合は送信側はあらかじめ受信側が5555で待ち受けていると知っています。送信側が知らない場合に、どうやって受信側のポート番号を知らせればよいのでしょうか?

http://www.hellohiro.com/datagram.htm

Aベストアンサー

#1です。

> 受信側は
> DatagramSocket
> を引数なしでインスタンス化して、receiveメソッドを動かせば、そこに返ってくる、ということなのでしょうか?

「返ってくる」というのはレスポンスのことでしょうか。その前提で話をします。

最初の回答のA→B(リクエスト)とB→A(レスポンス)のうち,Aがこの質問のとおりに動作するには,Bが以下のような動作を行う必要があります。逆にBが以下のような動作をするならAの動作はご質問のとおりです。

1)Aは引数なし,Bは固定のポートを指定してインスタンス化。
2)Aは送信するリクエストパケット(DatagramPacket)を作り,これにBのIPアドレスとポートをセットして送信。
3)BのIPアドレス・ポートにAからのパケット到着。Bはこれをreceiveメソッドで受け取る。
4)BはAからのパケットに含まれるAのIPアドレスとポート番号を取得する(DatagramPacketのgetSocketAddressメソッドで多分取得可)。
5)Bはレスポンスを作成し,取得したAのIPアドレスとポートをレスポンスパケット(DatagramPacket)にセットしてこれを送信。
6)AのIPアドレス・ポートにBからのパケット到着。Aはこれをreceiveメソッドで受け取る。

UDPでは,リクエストを送って相手がそれを受け取れば,UDP通信はそれでおわりです。リクエストに対してレスポンスを返す場合,送信側と受信側が入れ替わって新規のUDP通信を始めることになります。

#1です。

> 受信側は
> DatagramSocket
> を引数なしでインスタンス化して、receiveメソッドを動かせば、そこに返ってくる、ということなのでしょうか?

「返ってくる」というのはレスポンスのことでしょうか。その前提で話をします。

最初の回答のA→B(リクエスト)とB→A(レスポンス)のうち,Aがこの質問のとおりに動作するには,Bが以下のような動作を行う必要があります。逆にBが以下のような動作をするならAの動作はご質問のとおりです。

1)Aは引数なし,Bは固定のポートを指定し...続きを読む

QTCP/IP のパケットの分断と結合について

linux で socket を使ってプログラムを作っております。
パケットの頭に、どんな種類のパケットかの情報を入れ、それに続く部分にデータを入れて送っております。受信側では、届いたパケットの頭の情報を見て必要な処理を行う、という流れになっております。
ところが、時々、次のような現象が発生して困っております。

・送信側で一回のsendで送ったはずのデータが受信側では一回のrecvで届かず、二回のrecvで届く。
・送信側では二回のsendで送ったつもりなのに、受信側では一回のrecvで2つのパケットが結合したデータが届く。

これはsendとrecvでは普通に起こると想定しなければならない現象なのでしょうか?
それとも、linuxマシンの設定に問題があるのでしょうか?

Aベストアンサー

>・送信側で一回のsendで送ったはずのデータが受信側では一回のrecvで届かず、二回のrecvで届く。
>・送信側では二回のsendで送ったつもりなのに、受信側では一回のrecvで2つのパケットが結合したデータが届く。

TCPは「ストリーム」なのでそういう動作をしても不思議ではない。
ということになります。

>それとも、linuxマシンの設定に問題があるのでしょうか?

Windowsでも普通に発生します。

http://www.ne.jp/asahi/hishidama/home/tech/socket/tcp.html
send(送信)、recv(受信)や
http://www.ne.jp/asahi/hishidama/home/tech/socket/index.html#%E9%9B%BB%E6%96%87%E3%81%AE%E7%B5%82%E4%BA%86%E6%A4%9C%E7%9F%A5
等を参照…でしょうか。
# 他にもそういった解説をしているページはあるでしょう。
http://rgv250.dyndns.org/socket.htm

http://hp.vector.co.jp/authors/VA019876/sokrpg/doc/SockFAQ/sfaq01.html
の「たまに、受信したレコードの最後が途中で切れていることがあります。どうしてでしょうか? 」とか…

>・送信側で一回のsendで送ったはずのデータが受信側では一回のrecvで届かず、二回のrecvで届く。
>・送信側では二回のsendで送ったつもりなのに、受信側では一回のrecvで2つのパケットが結合したデータが届く。

TCPは「ストリーム」なのでそういう動作をしても不思議ではない。
ということになります。

>それとも、linuxマシンの設定に問題があるのでしょうか?

Windowsでも普通に発生します。

http://www.ne.jp/asahi/hishidama/home/tech/socket/tcp.html
send(送信)、recv(受信)や
http://www.ne.jp...続きを読む

QWinsockで接続待ちタイムアウトを設定する方法

現在、WinsockAPIを使ってソケット通信プログラムを作っています。
 このプログラムの仕様の中で、接続待ちタイムアウトというものがあります。これはつまり、connect関数を実行してから応答が返ってくる(関数が値を返す)までの時間監視のことなのですが、そのような値をソケットに対して設定する手段というのはあるのでしょうか?

Aベストアンサー

あるとすれば、
setsockopt()
で設定できるソケットオプションのどれかということになります。
明確に書かれているものはありませんが、もしかすると、送信タイムアウトの設定で効いてくるかも知れません。

なければ、
(1)ソケットをノンブロッキングにして、
(2)connect()の完了を、タイマを掛けることのできるselect()で待ち、
(3)自分のタイムアウトが先にやってきたら、ソケットを捨てて、タイムアウト処理をする。
connect()の結果がタイムアウトで完了してもなお自分のタイマに残りがあれば、残り時間分のタイマを掛けて(2)に戻る。
というような実装になるように思います。

回答になっておりませんが、参考まで。

QUDP通信におけるbind関数について

初めて質問させていただきます。よろしくお願いします。

最近、ネットワークプログラミングの勉強をしているのですが、bindについてよくわからなくなってきました・・・。よろしければご教授願います。

質問内容は以下の通りです。
(1)bindにおける設定内容は、「相手側のIPとポート番号」なのか「自分側のIPとポート番号」なのか?
 色々なところを調べてみましたが、「IPとポート番号」を設定する、としかかかれてなく、いったいどっちなのかがわからなくなってきました・・・。

(2)UDP通信において、bindは必要なのか?
 サーバ-クライアントの関係が曖昧なUDP通信において、bindというのは必要なのでしょうか。
私の認識では例えば、「recv関数」などを使い受信待ちをする場合はbindが必要だが、送信だけの場合には不要であるとなっています。

この認識はあっているのでしょうか。
拙文ですが、どうか教えていただきたく <(_ _*)>

Aベストアンサー

TCP/UDP通信がどのように働くかを考えれば、疑問の答えが分かるのでは?
bindについて言えば
「OSはマシンに届いたパケットを如何にして該当プログラムに届けるか?」
です。
自分のポート番号をOSに教えてあげなければ、OSは着信したパケットをどのプログラム(プロセス)に届けるか分からないでしょう。それをするのがbindの役割です。
従って(1)は自ポート番号。IPは複数IPを持っているマシンで一部IPでのみ受け付ける場合に必要ですね。
一般的にサーバでbindするタイミングでは相手のIPやポート番号は不明ですから、要求されても困りますね。
(2)は質問者さんの認識通り。受信のために必要、送信では不要です。

Qビルド時にinet_ptonが見つからないエラー

IPv6対応でinet_ptonを利用したのですが、下記ビルド時にエラーが発生します。

error C4013: 'inet_pton' undefined; assuming extern returning int

調べた結果下記のヘッダファイルとライブラリーを読みこめばいいという
記載を見かけて、追加したのですが、それでも同様のエラーが発生します。
(下記に関するエラーはなかったので、"ws2_32.lib" に対してはリンクが通っていると思います。)

#include <Ws2tcpip.h>
#pragma comment( lib, "ws2_32.lib" )

ご教示のほどよろしくおねがいします。

環境:
Windows7 64bit
WDK7.1

Aベストアンサー

WDK使ったことはありませんが……。

Ws2tcpip.hのinet_pton()のプロトタイプ宣言周辺を見ると…

>#if (NTDDI_VERSION >= NTDDI_VISTA)
>WINSOCK_API_LINKAGE
>INT
>WSAAPI
>inet_pton(

となっています。
NTDDI_VERSIONの設定次第で、後のプロトタイプ宣言は無効になるワケで……。
NTDDI_VERSIONはどう設定されています?
http://msdn.microsoft.com/ja-jp/library/windows/hardware/ff554695%28v=vs.85%29.aspx
http://k639.blog121.fc2.com/blog-entry-46.html

QGetPrivateProfileStringでiniファイル読込む処理を詳しく知りたいのですが・・・

お世話になっています。

iniファイルを読込み、各変数に代入するC言語のDLLを作成したいのです。
このサイトの投稿や、MSDNなどにも載っていたのですが、
少し理解に苦しみます。

現在まで、理解した点がwindows.hのインクルードを
記述するところ辺りです。
iniファイルは下記のようなレイアウトです。

---<mst.ini>----------------------------
[user]
name=username
ID=userid
[pc]
pcname=FMV
----------------------------------------

#include<windows.h>は記述することまでは
分かりましたが、以下から進みません。。。

GetPrivateProfileString("")

初心者で申し訳ありませんが、お助け願います。

Aベストアンサー

こんにちは。itohhといいます。

サンプルを載せておきます。

mst.iniファイル内の[user]セクションのnameキーの値を取得する。
DWORD dwLen=0;
char strBuf[100];
dwLen = GetPrivateProfileString("user",       // セクション名
                "name",       // キー名
                "soushi_ni",     // デフォルト値
                strBuf,       // 読み込んだ値を格納するエリア
                sizeof(strBuf),   // 上記のエリアのサイズ
                "mst.ini" );     // iniファイル名

解説:
iniファイル名をフルパスで指定しないとWindowsのディレクトリにあるものと判断されます。
Win9xなら「c:\windows」、WinNT系なら「c:\WinNT」。

[user]セクションのnameキーがないときは、デフォルト値で指定した値が設定させます。

復帰値「dwLen」は実際に設定した値(文字列)の長さが返されます。

こんにちは。itohhといいます。

サンプルを載せておきます。

mst.iniファイル内の[user]セクションのnameキーの値を取得する。
DWORD dwLen=0;
char strBuf[100];
dwLen = GetPrivateProfileString("user",       // セクション名
                "name",       // キー名
                "soushi_ni",     // デフォルト値
                strBuf,       // 読み込んだ値を格納するエリア
             ...続きを読む

QUDP通信での受信方法について

MFCでUDPプロトコルを使ったサーバー・クライアントをソケットプログラムで書いております。

ソフトの内容は、クライアントから送信されたの文字列のコマンドをサーバで処理をするだけです。

サーバー側での受信の仕方は
WSAAsyncSelect()関数を使ってソケットイベントが発生するごとに親ウィンドウに自作のメッセージ(WM_MY_MSG)が送られるように設定する



WM_MY_MSGのメッセージハンドラ内でrecvfrom()関数を使って受信する。

という方法を用いています。クライアント2台ぐらいであれば正常に動きます。


質問1:
まだ試したことはないのですが(というより試す環境がない)、ほぼ同時ぐらいに複数(10台ぐらい)のクライアントからコマンドが送信された場合、それを全部正確に受信できるものなのでしょうか?要するに一つのコマンドを処理中に別のコマンドが送られてきた場合の動作はどうなるのでしょうか?

質問2:
UDP通信での受信をする場合の何かもっとスタンダードな方法があるのでしょうか?

よろしくお願いします。

MFCでUDPプロトコルを使ったサーバー・クライアントをソケットプログラムで書いております。

ソフトの内容は、クライアントから送信されたの文字列のコマンドをサーバで処理をするだけです。

サーバー側での受信の仕方は
WSAAsyncSelect()関数を使ってソケットイベントが発生するごとに親ウィンドウに自作のメッセージ(WM_MY_MSG)が送られるように設定する



WM_MY_MSGのメッセージハンドラ内でrecvfrom()関数を使って受信する。

という方法を用いています。クライアント2台ぐらいであれば正常...続きを読む

Aベストアンサー

普段はMFCのSocketではなく
Winsockを使っていますが基本は同じだと思いますので参考までにコメント致します。

質問1:
同時に複数のクライアントからUDPパケットが送信された場合、
データはまず受信側のSocketのキューに格納されます。
なので1つのコマンドを処理中に別の(次の)コマンドを受信しても問題ありません。キューに格納されます。
シーケンシャルにキュー内からコマンドを取り出し終えるまで同じ処理を続ければ良いかと。

質問2:
MFCのSocketは古いVersionのSocketで、
困った記憶があります。v1.1?
(最新情報ではないかもです)
Winsockに関する良い書籍が出てますので
そちらを直接利用されてはどうでしょうか?
http://bookweb.kinokuniya.co.jp/htm/4797306882.html

UDPはコネクションレスですし、難しいことはないと思います。

参考URL:http://bookweb.kinokuniya.co.jp/htm/4797306882.html

普段はMFCのSocketではなく
Winsockを使っていますが基本は同じだと思いますので参考までにコメント致します。

質問1:
同時に複数のクライアントからUDPパケットが送信された場合、
データはまず受信側のSocketのキューに格納されます。
なので1つのコマンドを処理中に別の(次の)コマンドを受信しても問題ありません。キューに格納されます。
シーケンシャルにキュー内からコマンドを取り出し終えるまで同じ処理を続ければ良いかと。

質問2:
MFCのSocketは古いVersionのSocketで、
困った記憶...続きを読む

Qマルチスレッド間でデータ交換をする方法

マルチスレッドの知識がないままに、プログラミングをする必要が出てしまったのですが、書籍などで調べても分からない部分があるため、質問いたします。

Win32APIを用いて(MFCは使用しない)、WindowsでVC7.0環境です。

やりたいことは、
スレッドAとスレッドBを生成し、
スレッドAの終了時点で、スレッドBがスレッドA内部で生成したクラスのインスタンスを取得するというものです。(もしくはその逆)

スレッドAとB自体もクラスで構成しており、内部で生成されるインスタンスはグローバルではないため、スレッドBからスレッドAを見えるような仕組みが必要なのでしょうか??

まだイメージだけの段階で、ソースコードで表現できなくて申し訳ないのですが、簡単にご教授くださる方、もしくは参考になるサイトを教えてくださる方がいらっしゃいましたら、お願いいたします!

Aベストアンサー

スレッド間でデータ(メモリ空間)は共有されます。

なので,
どのスレッドからも,同じようにデータにアクセスできます。

goopon さんの質問内容は,スレッド間というよりも,クラスのインスタンス間でのデータ交換になると思います。

クラス Y のインスタンス y で生成したデータを,
クラス X のインスタンス x で使いたければ,
例えば,x の生成時に y へのポインタを渡しておいて,それを使って,y のメンバ関数を呼び出したりしますよね?

これは,マルチスレッドでも,シングルスレッドでも同じことです。

ただし,気をつけないといけないのは,
スレッド A から y のメンバ関数を呼び出すと,スレッド A で処理が行われ,
スレッド B から y のメンバ関数を呼び出すと,スレッド B で処理が行われるということです。
つまり,A と B から同時に y のメンバ変数を書き換えたり,
A が読んでいる最中に B が書き込んだりといったことが起こり得ます。
こうなると,データの整合性が取れなくなる恐れがあるので,
スレッド間の同期を取ったり(排他制御をしたり)する必要があります。

スレッド間でデータ(メモリ空間)は共有されます。

なので,
どのスレッドからも,同じようにデータにアクセスできます。

goopon さんの質問内容は,スレッド間というよりも,クラスのインスタンス間でのデータ交換になると思います。

クラス Y のインスタンス y で生成したデータを,
クラス X のインスタンス x で使いたければ,
例えば,x の生成時に y へのポインタを渡しておいて,それを使って,y のメンバ関数を呼び出したりしますよね?

これは,マルチスレッドでも,シングルスレッドで...続きを読む

Qルーターにつながっている全ての器機のIPアドレスを調べる方法

DHCP機能で振り分けらた全ての器機のIPアドレスを調べる方法はありませんか??

コマンドプロンプトから調べれるコマンドのようなものがあれば教えて頂きたいのですが、、、。


ルータはNTT製品の NVIIIです。

Aベストアンサー

DHCPからの貸し出し先だけでよければおそらく
DHCPのサーバーに貸し出し中のリストをもっています。
ルータがDHCPサーバーでしたら説明書をよんでみて
ください。
dhcpdなど立てていたらvarのどこかにdhcpd.leases
があるとおもいます


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング

おすすめ情報