LinuxのTCPIP実装についての疑問

このQ&Aのポイント
  • LinuxのTCPIP実装について疑問があります。受信バッファにデータが残っている状態でSocketのCloseが行われるとRST送信となり、FIN送信にならないということが分かりました。また、送信バッファにデータが残っていた場合もRST送信されるため、送信バッファのデータは破棄されずに送信されないのか疑問です。
  • 実際に試してみると、受信バッファと送信バッファのどちらにもデータが残っている場合にRST送信され、送信バッファのデータも送信されないことが分かりました。一方、受信バッファにデータが残っていない状態で送信後すぐにCloseしても、送信が完了してからFINが送信されるように見えます。
  • 受信バッファの有無によってCloseの挙動が変化し、受信バッファにデータがある場合はRST送信され、データも破棄されます。一方、受信バッファにデータがない場合はFIN送信され、送信完了後にFINが送信されます。この違いはKernelの実装によるものであり、送信バッファにデータが残っている場合はRSTではなくFINが送信されない点が疑問です。
回答を見る
  • ベストアンサー

LinuxのTCPIP

LinuxのTCPIP実装についてご教示ください。 (C言語をベースとして記載します) 例えば、Kernelとしてはデータを受信していて、アプリケーションがrecv()等の関数で データを引き抜いていない状態でのSocketのCloseはRSTの送信になりFINにはならないと 理解しています。 このとき、send()にデータが残っていた場合でもRST送信するのだから、 送信バッファのデータは破棄され、送信されないというKernel側の実装になっている という理解で良いのでしょうか? #送信バッファのデータというのは、アプリケーション側がsend()しており、実際にパケットは #送信されていない状態(パケットキャプチャされていない状態)としてください 手元で試していると、受信バッファにデータが残っている、かつ送信バッファにも 残っている場合はRST送信され、送信バッファにあるデータも送信されない 受信バッファにデータが残っていない状態で送信後すぐにCloseしても送信が完了してから FINされるように見えています。 ずらずらと書いたのですが、要は受信バッファにデータがある・なしでClose()の挙動が変わり RST送信か、FIN送信になるというのはWeb上でKernelの実装によるものというのを 見つけましたが、その状態、かつ送信バッファにデータが残っている場合は、 RSTだと送信されず、FINだと送信されないという違いがあるので、 Kernel側の意図された実装なのかどうかを知りたいです。

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

  • ベストアンサー
回答No.1

これを見たら解決? http://lxr.linux.no/#linux+v3.7.3/net/ipv4/tcp.c#L2046 IPv4だけでなく、IPv6でもこれを使ってcloseしているように見えます。 http://lxr.linux.no/#linux+v3.7.3/net/ipv6/tcp_ipv6.c#L2021 ざっと見た感じで間違っているかもしれませんが、RSTを投げるのは receive queue にデータがあるときのように見えますが。 参考までにこれもご覧ください。 http://lxr.linux.no/#linux+v3.7.3/include/net/sock.h#L205

f_attck
質問者

お礼

ご回答ありがとうございます。 当方は、Kernelの知識が無いのですが、 コードを読む限り、ご教示頂きましたように 受信バッファにデータがある場合にRSTになるように見えました また、FINになる場合には、tcp_send_fin()でqueueの 最後にFINを入れているように見えるので、すでにsend()等で skbに入っているものは送信されるように見えたので 質問で書かせて頂いた受信バッファのある・なしでの Closeの挙動、かつ送信バッファにデータが存在する場合の 挙動もコード通りということですね

関連するQ&A

  • UDPパケットのバッファサイズ変更について

    いつも参考にしています。 UDPパケットのバッファサイズ変更についてご教示下さい。 OS:Turbolinux 10 Server(kernel 2.6.8-6smp) サーバでIPv6のUDPパケットを受信しているのですが、負荷をかけると取りこぼしが発生しています。 (秒間300パケットほどの負荷をかけると2割ほどのパケットには応答がありません) アプリ側のログにパケットを破棄したというものがないので、kernelのバッファサイズを疑っているのですが、 IPv6でUDPのパケット(tftpです)のバッファサイズを増やすにはどのようにすればよいでしょうか。 ※負荷をかけているときにnetstat -iで見ると破棄しているパケットはありませんでした。この場合はkernelチューニングは無意味なのでしょうか? ご回答お願いします。

  • 特定文字カウント機能について

    送信側から受信側にパケットを送信するプログラムを作りました。 受信側では、送信側から送信されたパケットは、data関数内で処理されるようにしました。 そこで、「send」文字を付加したパケットだけカウントするようにしたいのですが、どのように記述すればよいか教えていただけないでしょうか? void main(){ data(); } void data_packet(){ int d=0; if(equals(message,(send*)"test",strlen("send"))){ d++; } printf("カウント数:%d\n",d); } 上記に示したプログラムの場合、data関数が呼ばれるたびに、int d=0より、0へと戻ってしまいます。なにか方法はありますでしょうか? よろしくお願いします。

  • SocketのSend関数でのCLOSEの検知 [Linux]

    Linux環境でSocket(dm:PF_INET,type:SOCK_STREAM)を使用しての、 Client&ServerプログラムをCで作成しているのですが、 そこでのSend関数の使い方についてご助力ください。 Client&Serverプログラムは下記のような動きをします。 [Client] ServerへConnectした後、複数のDataを数秒間隔でServerへ 送信(send関数使用)します。受信(recvやread関数等)は、 一切行いません。 [Server] ClientからのConnectを受け付けた後、Clientから受信(recv関数 使用)したDataを標準出力へ表示する。送信(sendやwrite関数 等)は、一切行いません。 さて、ここでもしClientプログラムがCloseを発行したり、マシン DOWN等の理由でConnectionが切断され、Server側のSocketが CLOSE_WAIT状態になった場合、Bufferに溜まっていたDataを すべて受けきった後、recv関数が0を返してくれるので 相手が終了したことがわかります。 ここからが質問のMainです。 では、もしServerプログラムがCloseを発行したり、マシン DOWN等の理由でConnectionが切断され、Client側のSocketが CLOSE_WAIT状態になっても、CLOSE_WAIT直後のsend関数が なぜか正常に処理されてしまいます。無論このDataは、 Server側は受け取りません。この次のsend関数実行時に EPIPEが返ってくるので、ここでようやくSocketが切断された ことが判ります。 これを何とかCLOSE_WAIT状態になった直後から、send関数で 切断を検知できるようにできないでしょうか。 よろしくお願いします。 以上

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

    linux で socket を使ってプログラムを作っております。 パケットの頭に、どんな種類のパケットかの情報を入れ、それに続く部分にデータを入れて送っております。受信側では、届いたパケットの頭の情報を見て必要な処理を行う、という流れになっております。 ところが、時々、次のような現象が発生して困っております。 ・送信側で一回のsendで送ったはずのデータが受信側では一回のrecvで届かず、二回のrecvで届く。 ・送信側では二回のsendで送ったつもりなのに、受信側では一回のrecvで2つのパケットが結合したデータが届く。 これはsendとrecvでは普通に起こると想定しなければならない現象なのでしょうか? それとも、linuxマシンの設定に問題があるのでしょうか?

  • Linuxでパケットのデータ部分を合成するプログラムを教えてください。

    LinuxでC言語を使用しているのですが、パケットのデータ部分を合成するプログラムのを教えてください。 具体的な例として、 端末A,B,Cがあり、AはBを中継して、CにUDPパケットを2個送信します。 中継端末のBは2個のUDPパケットをバッファリングした後、データ部分のみを1個のパケットにまとめてCに送信します。(ヘッダ部分はAが送信したときと同じにしたい) Cは2個分のデータが入ったUDPパケットを1個受信する。 この例の端末Bでのプログラムを書くとするとどのようにすればいいのでしょうか?? よろしくお願いしますm(_ _)m

  • ソケットプログラミング(配列について)

    こんにちは。 この掲示板に、大変お世話になっています。 私は送信側から受信側へWindows上でUDPソケットを利用し、約3MByteのmpegデータを、1024Byteずつパケットに分割し送信しています。以下に、送信側のプログラムの概要を示します。 [送信側] ・配列[1025]確保し、fread関数を用いてファイルの読み込みを行い、sendto関数で受信側へ送信。 ・1024Byteずつ送出できているかを表示。 ・送出した1024Byteのパケット数を表示。 int n; int Num_n = 0; char send_buf[1025]; while((n = fread(send_buf,1,DATA_SIZE,fp)) != 0){ Num_n++; //1024Byteずつ送出できているかを表示させています printf("n:%dバイト\t",n); sendto(theSocket,send_buf,n,0,(LPSOCKADDR)&saServer,sizeof(struct sockaddr)); } //送出したパケット数を表示させています printf("%d個のパケットを送出しました\n",Num_n); <質問内容> 約3MByteのmpegを1024Byteずつ送信した場合、最後のパケットは、「n:4バイト」と表示されました。残りの1020バイト分は、どのような形で送信されているのでしょうか?確保した配列内に何も入っていない形で送信されているのでしょうか? また、私は送信側と受信側でスループットの計算を以下の式から算出しています。 送信側 (送信したパケット数×1024×8)/送信に要した時間 受信側 (受信したパケット数×1024×8)/受信に要した時間 送信したパケット数は3041個。 送信に要した時間=受信に要した時間です。 この場合、送信側での計算として・・・ (3041×1024×8)/送信に要した時間とするのか (3040×1024×8)+4/送信に要した時間とするのか どちらが正当なのでしょうか? よろしくお願いします。

  • TCPの通信において、受信バッファから上位アプリケーションへデータを渡

    TCPの通信において、受信バッファから上位アプリケーションへデータを渡すタイミングについて教えてください。 PSHフラグが立っているデータを受信すると上位アプリケーションへ渡すというのは学びましたが、その他どのようなタイミングで上位アプリケーションへデータを渡すのかわからなかったため質問させていただきました。 例えば、PSHフラグのデータが来る前に受信バッファがいっぱいになってしまったら、受信側で勝手にデータを渡してしまうのでしょうか。(それともバッファがいっぱいになると送信側がPSHフラグを送ってくれるのでしょうか。でもゼロウィンドウプローブを考えるとそれもない気がします。) また、TCPでの通信部分なため、このあたりの動作に関してはアプリケーションごとではなくOSに依存するのかなと思っており、アプリケーションとしてはどのような塊(タイミング)でデータを受信してもちゃんと処理できるのかなというのも気になります。 「現在はPSHフラグを無視している」というのもネット上で見かけましたが、そうするとますますOSの独断でデータをアプリケーションに渡しているのかなと思いました。 このあたりがよくわからなかったので、ご教授願えればと思います。 ※スライディングウィンドウ、ゼロウィンドウについてはネットですぐ見つかる程度の範囲では理解しているつもりです。

  • FIN,ACKとACKについて

    はじめまして。5月よりTCPソケット通信を勉強しているものです。 クライアントとサーバーのプログラムを作り試行錯誤しながら動かしているのですが一つ不思議な現象が起きたので質問させて頂きます。 処理が終わり、通信を切断する時なのですが、ソケット通信に関連する書籍やWebページを見ていると接続を切断するときにFIN,ACKを送信して相手側がACKを送信し、FIN,ACKを送信して最後にACKを送信するとなっています。図にすると以下のような感じでしょうか。 PCA       PCB FIN,ACK送信 → FIN,ACK受信 ACK受信   → ACK送信 FIN,ACK受信 → FIN,ACK送信 ACK送信   → ACK受信 この手順でPCA,PCBともに切断されるとあるのですが、自分が作ったプログラムを実行させて、etherealでパケットをモニタリングすると以下のような状態で終わってしまいます。 PCA       PCB FIN,ACK送信 → FIN,ACK受信 FIN,ACK受信 → FIN,ACK送信 ACK送信   → ACK受信 PCAからのFIN,ACK受信に対してのACKの送信が省略されて、いきなりFIN,ACKを送信してしまいます。その後PCAからはACKが返されて終了となります。 プログラム的には希望通り動作しているので問題は無いのですが、なぜ途中のACKが省略されてしまうのか原因が知りたいです。また、自分の認識が間違っている場合のご指摘等頂ければと思います。 つたない文章で申し訳ありませんがご存知の方がいらっしゃいましたら教えて下さい。

  • winsockの非同期通信のsendイベント

    winsockの非同期通信で、 case FD_WRITE: にsend()関数を書いて送信させるのはごく普通のやりかたですね。 このイベントは、 接続直後と、送信バッファが一杯だった状態から送信が可能な状態に復帰したときに 呼ばれますよね。 これだと、ユーザーが好きなタイミングで、データを送信しようと思った時に送信できません。 でも100MBなんて大きなデータを送ると、送信バッファが溢れるので、 case FD_WRITE: にsend()を書きたい。 こういうとき、どのようにコードを書くのが、よろしいのでしょうか。

  • TCP/IPのデータ送受信の"確実性"はどの程度??

    Winsock2を使ってソケットプログラミングをするため通信プロトコルを考えています。そこでソケットの挙動について疑問があります。 sendを複数回使って以下のバイト数のデータを送信したとします。 1.3byte送信[AAA] 2.5byte送信[BBBBB] 3.3byte送信[CCC] このとき正常に通信ができたときは受信側では1~3回のrecvによって [AAABBBBBCCC] というデータが受信できると思います。ここまではいいのですが、疑問があるのは送受信に異常があった場合です。 1.send単位で欠落(再度connectの必要なし)。損失受信データ例[AAACCC]、[BBBBBCCC] 2.TCP上での送信パケット単位で欠落(再度connectの必要なし)。損失データ例[AAABB] 3.send単位で欠落して以後は全て欠落(再度connect必要あり)。損失データ例[AAABBBBB]、[AAA] 4.TCPのパケット単位で欠落して以後は全て欠落(再度connect必要あり)。損失データ例[AAABB] おそらくこれらのいずれかの方法でデータが欠落することになるかと思います。データの再送信をするのであればconnectが必要になるのかという点も分かりません。 ソケットがcloseになったという理由によるデータ欠落であれば4番になるかと思いますが。。。@FreeDのようにドーマントに入るようなネットワークの場合単純にcloseを期待することもできないような気がしますし。。。 どなたか教えていただけないでしょうか?よろしくお願いします。