QA@IT
«回答へ戻る

回答を投稿

誤解があったようですので、ご説明させていただきます。

ご存じかと思いますが、UDPはその名のとおり、データグラム単位で送受信を行うプロトコルです。これに対して、TCPはバイトストーム型で、バイト単位で送受信を行うプロトコルです。

UDPではデータグラム単位(意味をなすデータの塊)で送受信することができます。
例を挙げますと、アプリケーションが「AAAA」と「BBBB」という2つの意味をなす塊であるデータグラムをUDPを使用して、2回送信した場合、受信側でも2回受信することにより、
「AAAA」、「BBBB」という2つの意味をなす塊として、それぞれ受信することができます。

これに対してTCPでは意味をなす塊であるデータグラムという単位は意識されず、単にバイト列として扱われます。受信側でも同様に単にバイト列として扱われます。
例を挙げますと、アプリケーションが「AAAA」と「BBBB」という2つの意味をなす塊であるデータグラムをTCPを使用して2回にわたり送信した場合、受信側では1回の受信で「AAAABBBB」という単位で受信する場合があり、また、3回の受信で「AAA」、「ABB」、「BB」と単位で受信する場合もあります。つまり、単なるバイト列として送受信され、送信回数と受信回数には何ら関係はないのです。意味をなす塊で2回送信したので、2回受信すれば、意味をなす塊でそれぞれ受信できるとは言えないのです。
TCPでは、「AAAA」、「BBBB」という本来意味をなす塊(データグラム)に関する情報はなく、
このため、受信側アプリケーションでは受信されたバイト列を意味をなす塊(データグラム)に分ける必要があります。

TCP、UDPともに下位のレイヤーとしてIPを使用しますので、IP層でのフラグメント化やフラグメント化されたパケットの再構築については基本的には同様です。(少し荒っぽいですが。)
送信側では意味のある塊が意識できているので問題はないのですが、受信側で意味のある塊として受信できるかが異なります。
これは、受信側でどのような状態で受信されるかということかと思います。
実装上のお話になりますが、UDPでは各ソケットは受信バッファを持ち、
ソケットに対して到着した「データグラム」はそのソケットの受信バッファに格納され、
プロセスがrecvfrom(C言語)を呼び出すと、このバッファからFIFO順序で次のデータグラム(意味をなす塊)が返されます。
TCPでも同様に各ソケットは受信バッファを持ち、ソケットに対して到着したデータがそのソケットの受信バッファに格納されます。プロセスがrecv(C言語)を呼び出すとその時点で受信バッファに格納されているバイト列が返されます。つまり、意味をなす塊では返されません。

長文になってしましましたが、以下の文言の意味するところをご理解いただけましたでしょうか。

UDPを使用して送受信してしたメッセージの塊をTCPを使用して送受信した場合、
その塊の区切りは判断できないと思っています。

また、ご意見をいただきました以下のような発想でもありません。

通常、TCP(STREAM)の方が信頼がおける通信であり、UDP(DGRAM)の方が整合性を
失いやすい通信です。なぜUDPだと可能なものがTCPだと無理だと思われたのでしょうか
(普通は逆ですね)

UDP、TCPはそれぞれ固有の特性をもっています。それぞれの特性に応じた使い方をすれば良いと思っています。例えば、今日のインターネットの基盤を支えるDNSへの問合せでは、ご存じのとおりUDPが使用されています。TCPがUDPよりも優れているという発想もありません。
単にTCPを使用する際は、バイトストリーム型であるため、その中から意味のある塊を適切に取り出す、あるいは不適切なものを排除する適切な方法がないかと思いお知恵を拝借した次第です。

以下、ご質問をいただいております回答になりましたでしょうか。
今回、ご質問をさせていただいた主旨ですが、UDPでもフラグメンテーションはされますので、小分けでしか送れないという点ではありません。誤解を招いたのであれば申し訳ありませんでした。

ですから「UDPだと塊で送れて安心、TCPだと塊は送れない小分けでしか送れないから
どうしよう」という発端であればそれがそもそも勘違いではないかと思うのですが
どうでしょう。

誤解があったようですので、ご説明させていただきます。

ご存じかと思いますが、UDPはその名のとおり、データグラム単位で送受信を行うプロトコルです。これに対して、TCPはバイトストーム型で、バイト単位で送受信を行うプロトコルです。

UDPではデータグラム単位(意味をなすデータの塊)で送受信することができます。
例を挙げますと、アプリケーションが「AAAA」と「BBBB」という2つの意味をなす塊であるデータグラムをUDPを使用して、2回送信した場合、受信側でも2回受信することにより、
「AAAA」、「BBBB」という2つの意味をなす塊として、それぞれ受信することができます。

これに対してTCPでは意味をなす塊であるデータグラムという単位は意識されず、単にバイト列として扱われます。受信側でも同様に単にバイト列として扱われます。
例を挙げますと、アプリケーションが「AAAA」と「BBBB」という2つの意味をなす塊であるデータグラムをTCPを使用して2回にわたり送信した場合、受信側では1回の受信で「AAAABBBB」という単位で受信する場合があり、また、3回の受信で「AAA」、「ABB」、「BB」と単位で受信する場合もあります。つまり、単なるバイト列として送受信され、送信回数と受信回数には何ら関係はないのです。意味をなす塊で2回送信したので、2回受信すれば、意味をなす塊でそれぞれ受信できるとは言えないのです。
TCPでは、「AAAA」、「BBBB」という本来意味をなす塊(データグラム)に関する情報はなく、
このため、受信側アプリケーションでは受信されたバイト列を意味をなす塊(データグラム)に分ける必要があります。

TCP、UDPともに下位のレイヤーとしてIPを使用しますので、IP層でのフラグメント化やフラグメント化されたパケットの再構築については基本的には同様です。(少し荒っぽいですが。)
送信側では意味のある塊が意識できているので問題はないのですが、受信側で意味のある塊として受信できるかが異なります。
これは、受信側でどのような状態で受信されるかということかと思います。
実装上のお話になりますが、UDPでは各ソケットは受信バッファを持ち、
ソケットに対して到着した「データグラム」はそのソケットの受信バッファに格納され、
プロセスがrecvfrom(C言語)を呼び出すと、このバッファからFIFO順序で次のデータグラム(意味をなす塊)が返されます。
TCPでも同様に各ソケットは受信バッファを持ち、ソケットに対して到着したデータがそのソケットの受信バッファに格納されます。プロセスがrecv(C言語)を呼び出すとその時点で受信バッファに格納されているバイト列が返されます。つまり、意味をなす塊では返されません。

長文になってしましましたが、以下の文言の意味するところをご理解いただけましたでしょうか。
>UDPを使用して送受信してしたメッセージの塊をTCPを使用して送受信した場合、
>その塊の区切りは判断できないと思っています。

また、ご意見をいただきました以下のような発想でもありません。
>通常、TCP(STREAM)の方が信頼がおける通信であり、UDP(DGRAM)の方が整合性を
>失いやすい通信です。なぜUDPだと可能なものがTCPだと無理だと思われたのでしょうか
>(普通は逆ですね)

UDP、TCPはそれぞれ固有の特性をもっています。それぞれの特性に応じた使い方をすれば良いと思っています。例えば、今日のインターネットの基盤を支えるDNSへの問合せでは、ご存じのとおりUDPが使用されています。TCPがUDPよりも優れているという発想もありません。
単にTCPを使用する際は、バイトストリーム型であるため、その中から意味のある塊を適切に取り出す、あるいは不適切なものを排除する適切な方法がないかと思いお知恵を拝借した次第です。

以下、ご質問をいただいております回答になりましたでしょうか。
今回、ご質問をさせていただいた主旨ですが、UDPでもフラグメンテーションはされますので、小分けでしか送れないという点ではありません。誤解を招いたのであれば申し訳ありませんでした。
>ですから「UDPだと塊で送れて安心、TCPだと塊は送れない小分けでしか送れないから
>どうしよう」という発端であればそれがそもそも勘違いではないかと思うのですが
>どうでしょう。