お勉強したので、要点だけまとめたメモです。
IP は、到達性を保障しないプロトコルです。 あて先の IP アドレスさえ指定すれば送れます。 また、IP パケットの大きさは可変です。 ただし、大きなパケットは途中で勝手に断片化される場合もあります。 到達性を保障したり、大きなデータを送受信するためには、複数の IP パケットを束ねて、別の決まり事にそって 通信します。これが TCP です。だから、TCP のパケットは同時に IP のパケットでもあります。 IP ヘッダの構造は以下のようになっています。
version
header len
service type
all the length
パケットのサイズは基本的に 1.5KB でしたが、もっと大きなパケットも 送れるようになっています。これを Jumbo Frame (ジャンボフレーム) といいます。
IP に関する Q & A
Q: IP パケットは、自分の IP アドレスを指定しなければ送れない? A: そんなことはない。例えば BOOTP/DHCP の一つ目のパケット。 ただし、ICMP の不達通知は着かないかもしれない。
Q: ICMP と IP の関係は? A: ICMP は IP を利用したプロトコル。ヘッダの構造・中継の方法は IP に準ずる。 ただし、IP 自体のフローを制御するため、ネットワーク層に属している。 IP パケットをある装置が次に転送できなかったとき、その装置が ICMP の不達通知を送る。
Q: ARP と IP の関係は? A: ARP は ICMP と同様、IP を利用したプロトコル。ヘッダの構造・中継の方法は IP に準ずる。 ただし、IP 自体のフローを制御するため、ネットワーク層に属している。 IP から MAC を知るのに用いられる。
TCP のパケットは、以下の要素からなっています。 (大事なものだけ抜き出しました)
送信元ポート番号 (16 bit)
送信先ポート番号 (16 bit)
シーケンス番号(32bit): ack は +1, その他は送信したサイズ分だけくわえる。
確認応答番号 (32bit) : 受け取ることが期待される、次のシーケンス番号。ACK が on のときのみ有効
ヘッダ長 (4bit)
フラグ (urg, ack, psh, rst, syn, fin) 緊急モードなど
window size
check sum
緊急ポインタ
TCP フラグは、以下のものが定義されている。 パケットの話しをするときは、「SYN」とか「RST」とか言葉が飛び交うから、覚えておきましょう。 例えばSYN パケット(シンパケット)とは、syn フラグが on なパケット、RSTパケット(リセットパケット)とは、RSTフラグが on なパケットです。
SYN 同期、このフラグが立っていたら、通信開始を意味する
FIN 通信終了
RST リセット。このパケットが来ると、"Connection closed by peer"というメッセージが出る
PSH 受信プロセスにできるだけ早くデータを送る (バッファリングを無効化)
TCP を使ってプログラミングをする時には、ソケット API を用います。 普段プログラムを書くときに目にするのは、以下のような関数 (API) です。
[サーバ側]
socket()
bind()
listen()
accept()
このうち、listen() まではマシン内
[クライアント]
socket()
connect()
[通信]
recv()
send()
TCP も IP のように、データにヘッダを付けて送ります。
[TCP ヘッダ] [TCP データ]
この一つを TCP セグメントと呼びます。 TCP セグメントは、多くの場合 IP パケット一つに対応します。 でも、絶対ではありません。IP パケットは、経路中のルータの都合で 勝手に断片化されてしまう場合があります。 例えば、断片化前がこんな感じだったとします。( 0123456789 がデータです)
[IPヘッダ] [TCP ヘッダ] [01234567890123456789]
断片化によって、この IP パケットは二つに分割されてしまいました。
[IPヘッダ] [TCP ヘッダ] [0123]
[IPヘッダ] [4567890123456789]
この場合、受け取り側ではこの二つの IP パケットを結合して、まず 正しい [TCPヘッダ] + [データ] という構造を復元します。その上で、 ポート番号などの意味を解釈します。 このセグメントの最大値を、MSS と呼びます。 MSS はコネクション確立時に決めて、1 セグメント = 1 パケットになるようにします。
TCP の元々のアイディアは、セグメントが正しい順番で確実に届くことを保障するため、 セグメント一つに対し必ず ACK を送受信します。 でも、これだと効率が悪いので、複数のセグメントに対する ACK をまとめて 返せるようになっています。これがウィンドウです。 ウィンドウサイズは、受信バッファサイズ以下でなければならないため、 希望するウィンドウのサイズを受信側が TCP ヘッダに乗せて送信します。 ウィンドウサイズを書く場所は、全ての TCP ヘッダに存在します。 ウィンドウサイズは通例 1 から始めます (スロースタート)
全二重の意味: 上り下り同時に使える (full-duplex)
ACK というのはフラグだから、パケットの内容と独立して送ることができる。 単に ACK だけを送りたいときには、IP 1 パケットを仕立てて、ACK のフラグを立てて送る。 でも、他に一緒に送るものがあるときには、送信データに ack をのせる (piggy pack) こともある。
基本の流れ。
C -> S SYN
S -> C SYN ACK
C -> S ACK
パケットを再送するのは、IP ではなくて TCP が面倒を見る話。 別にどのように再送しても規格違反にはならないのだが、推奨されている方法では 再送間隔は指数的に伸ばす。
nagel algorithm 小さな TCP パケットを、遅延に応じてまとめて送る 具体的には、ack が返ってくるまで次を出さない。 RTT が長いときにはまとめがちになる。 スループットはあがるが応答性が落ちるので、 X のような対話的なアプリでは off にする。
MTU: Maximum transmission unit (一回に送信できるデータの最大値) MSS: Max segment size (MTU からヘッダなどを除いたサイズ)
UDP と IP の違い:
ポート番号がある
UDP にはデータのチェックサムがある (IP には、ヘッダのチェックサムしかない)