TCPのセグメントとは?パケットとの違いも!(データ単位:トランスポート層:ヘッダ:ペイロード:MSS:分割など)
ネットワーク通信を学ぶ上で、「セグメント」「パケット」「フレーム」といったデータ単位の違いに戸惑う方は多いのではないでしょうか。特にTCPのセグメントは、トランスポート層における基本的なデータ単位であり、信頼性の高い通信を実現するための重要な仕組みを担っています。
本記事では、TCPセグメントの構造や役割を丁寧に解説するとともに、よく混同されるパケットとの違いも整理していきます。ヘッダ・ペイロード・MSS・分割といったキーワードもしっかり押さえながら、TCP通信の全体像を理解していきましょう。
TCPセグメントとは何か?その本質をまず押さえよう
それではまず、TCPセグメントの基本的な概念について解説していきます。
TCPセグメント(TCP Segment)とは、OSI参照モデルやTCP/IPモデルにおけるトランスポート層で扱われるデータ単位のことです。アプリケーションが送信したいデータは、そのままネットワークに流れるわけではなく、各層でそれぞれの単位に変換されながら送受信されます。
TCPはTransmission Control Protocol(伝送制御プロトコル)の略であり、信頼性・順序保証・エラー検出といった機能を提供するプロトコルです。このTCPがトランスポート層でデータをやり取りする際の単位が、まさに「セグメント」と呼ばれます。

TCPセグメントの基本構造
TCPセグメントは大きく「TCPヘッダ」と「ペイロード(データ部)」の2つで構成されています。
TCPヘッダには、通信を制御するためのさまざまな情報が含まれています。送信元ポート番号・宛先ポート番号・シーケンス番号・確認応答番号・フラグビット・ウィンドウサイズなどがその代表例です。一方、ペイロードはアプリケーション層から渡された実際のデータ本体を指します。
| フィールド名 | サイズ | 説明 |
|---|---|---|
| 送信元ポート番号 | 16ビット | 送信側のポート番号 |
| 宛先ポート番号 | 16ビット | 受信側のポート番号 |
| シーケンス番号 | 32ビット | データの順序管理に使用 |
| 確認応答番号 | 32ビット | 次に受信期待するバイト番号 |
| データオフセット | 4ビット | ヘッダの長さを示す |
| フラグ(制御ビット) | 6〜9ビット | SYN・ACK・FINなどの制御フラグ |
| ウィンドウサイズ | 16ビット | 受信バッファの空き容量 |
| チェックサム | 16ビット | エラー検出用 |
| 緊急ポインタ | 16ビット | 緊急データの位置を示す |
ヘッダとペイロードの役割の違い
ヘッダとペイロードはそれぞれ明確に異なる役割を持っています。ヘッダは「制御情報」、ペイロードは「実データ」と覚えておくと整理しやすいでしょう。
ヘッダに含まれるシーケンス番号は、複数のセグメントに分割されたデータを受信側で正しい順序に並べ替えるために使われます。また確認応答番号(ACK番号)は、受信側が「ここまで届きました」と送信側に伝えるための番号です。これらの仕組みによって、TCPは信頼性の高い通信を実現しています。
TCPセグメントが生成されるタイミング
アプリケーション層がデータを送信しようとすると、そのデータはトランスポート層のTCPに渡されます。TCPはこのデータを適切なサイズに分割し、各断片にTCPヘッダを付加してセグメントを生成します。
この「適切なサイズ」の基準となるのが、後述するMSS(Maximum Segment Size)です。データが大きい場合は複数のセグメントに分割され、それぞれ独立して送信されます。受信側はシーケンス番号を使ってこれらを元の順序に再組立てするという流れになります。
セグメントとパケット・フレームの違いを整理しよう
続いては、セグメント・パケット・フレームという3つのデータ単位の違いを確認していきます。
ネットワークの勉強をしていると、「セグメント」「パケット」「フレーム」という言葉が次々と登場し、混乱することがあります。これらはすべて「データのまとまり」を指す言葉ですが、それぞれ異なる層で使われる用語です。
パケットとは何か
パケット(Packet)はネットワーク層(IPレイヤー)で扱われるデータ単位です。TCPセグメントにIPヘッダが付加されたものがパケットとなります。IPヘッダには送信元IPアドレス・宛先IPアドレス・TTL(Time To Live)などが含まれており、ルータはこのIPヘッダを参照して次の転送先を決定します。
つまり、セグメントはパケットに内包されるという関係です。「パケット通信」という言葉が一般的に使われますが、厳密にはトランスポート層のデータ単位はセグメントと呼ぶのが正確です。
フレームとの違い
フレーム(Frame)はデータリンク層で扱われるデータ単位です。パケットにMACアドレス情報などを含むデータリンク層のヘッダ・トレーラが付加されたものがフレームです。LANケーブルや無線LANを通じて、隣接するノード間でやり取りされる単位がこのフレームとなります。
以下の表でそれぞれのデータ単位を整理しておきましょう。
| 層 | データ単位 | プロトコル例 | 付加される情報 |
|---|---|---|---|
| アプリケーション層 | メッセージ/データ | HTTP、FTP、DNS | アプリケーション固有のデータ |
| トランスポート層 | セグメント(TCP)/データグラム(UDP) | TCP、UDP | ポート番号、シーケンス番号など |
| ネットワーク層 | パケット | IP | IPアドレス、TTLなど |
| データリンク層 | フレーム | Ethernet | MACアドレスなど |
| 物理層 | ビット | (電気信号など) | 0と1の信号 |
カプセル化と分離の仕組み
データが送信される際、上位層から下位層へと順番にヘッダが付加されていきます。これをカプセル化(Encapsulation)と呼びます。逆に受信側では、下位層から上位層へとヘッダを取り除いていく「デカプセル化」が行われます。
この仕組みによって、各層は自分が担当する情報だけを処理すればよく、上位層や下位層の詳細を知らなくても動作できます。これがTCP/IPの設計における大きな特長のひとつといえるでしょう。
MSSとセグメントの分割について理解しよう
続いては、セグメントサイズを決める重要な概念であるMSSと、データ分割の仕組みを確認していきます。
MSS(Maximum Segment Size)とは、1つのTCPセグメントのペイロード部分が取り得る最大サイズのことです。単位はバイトで表され、TCPヘッダ自体のサイズは含まれません。この値を超えるデータは複数のセグメントに分割されて送信されます。
MSSの決まり方
MSSは、TCPコネクションを確立する際のスリーウェイハンドシェイクにおいてSYNパケットのオプションフィールドで通知されます。送信側・受信側それぞれがMSSを提示し、小さい方の値が採用される仕組みです。
一般的なEthernetの場合、MTU(Maximum Transmission Unit)は1500バイトです。ここからIPヘッダ(20バイト)とTCPヘッダ(20バイト)を引くと、MSSは通常1460バイトになります。
| 項目 | サイズ(バイト) | 説明 |
|---|---|---|
| Ethernet MTU | 1500 | Ethernetフレームのペイロード最大値 |
| IPヘッダ | 20 | オプションなしの場合 |
| TCPヘッダ | 20 | オプションなしの場合 |
| MSS(標準) | 1460 | 1500 – 20 – 20 = 1460バイト |
セグメントの分割と再組立て
送信したいデータがMSSを超える場合、TCPはそのデータを複数のセグメントに分割して送信します。各セグメントにはシーケンス番号が割り当てられており、受信側はこの番号を使って正しい順序にデータを並べ直します。
例えば、4380バイトのデータをMSS 1460バイトで送る場合は、3つのセグメントに分割されます。受信側はACK番号を返すことで「どこまで受信できたか」を通知し、送信側はその情報をもとに次のセグメントを送るかどうかを判断します。
以下はPythonを使ったTCPソケット通信の簡単なサンプルコードです。大きなデータを送信する際にTCPが自動的に分割して送ってくれる様子を確認するための例となっています。
import socket送信側(クライアント)のサンプル
TCPソケットを作成
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)サーバに接続(ローカル接続の例)
client_socket.connect(('127.0.0.1', 9000))3000バイトのデータを作成(ドラゴンフルーツのデータを模した例)
data = b'DragonFruit_data_' * 176 # 約3000バイトTCPが自動的にMSSに合わせて分割して送信する
client_socket.sendall(data)print("送信完了:", len(data), "バイト")
出力結果:送信完了: 2992 バイトclient_socket.close()
フラグメンテーションとの違い
似た概念としてフラグメンテーション(Fragmentation)があります。これはネットワーク層(IP層)でパケットが分割される仕組みです。TCPのセグメント分割はトランスポート層での処理ですが、フラグメンテーションはIPレベルでMTUを超えた場合に発生します。
現代のTCP実装では、パスMTU探索(PMTUD)によってルート上の最小MTUを事前に調べ、フラグメンテーションが発生しないようにMSSを調整することが一般的です。不要な分割を防ぐことで、通信効率を高める工夫がなされています。
TCPセグメントの実際の動きをシーケンスで確認しよう
続いては、TCPセグメントが実際の通信の中でどのように使われるか、その流れを確認していきます。
TCP通信は大きく「コネクション確立」「データ転送」「コネクション切断」の3フェーズで構成されています。各フェーズにおいて、どのようなセグメントがやり取りされるかを理解することが、TCP通信の全体像を把握する鍵となるでしょう。
スリーウェイハンドシェイクとセグメント
TCPコネクションを確立する際には、スリーウェイハンドシェイク(3-way handshake)が行われます。このプロセスでは3つのセグメントがやり取りされます。
最初にクライアントがSYNセグメントを送信し、「通信を開始したい」という意思を伝えます。次にサーバがSYN-ACKセグメントを返し、「了解した、こちらも準備OK」と応答します。最後にクライアントがACKセグメントを送ってコネクションが確立されます。このとき、MSSのネゴシエーションも同時に行われます。
データ転送中のシーケンス番号とACK
コネクション確立後のデータ転送では、シーケンス番号と確認応答番号が連携しながら動作します。送信側はシーケンス番号を使って「このセグメントは何バイト目から始まるデータか」を示し、受信側はACK番号で「次に欲しいのは何バイト目からか」を返します。
以下はPythonでサーバ側のソケットを実装し、受信データのサイズを確認するシンプルな例です。
import socket受信側(サーバ)のサンプル
TCPソケットを作成
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)ポート9000で待ち受け
server_socket.bind(('127.0.0.1', 9000))
server_socket.listen(1)print("クライアントの接続を待機中...")
conn, addr = server_socket.accept()
print("接続元:", addr)total_received = 01460バイト(MSS相当)ずつ受信するループ
while True:
# MSSに近いサイズでデータを受け取る(アボカドデータの受信を模擬)
chunk = conn.recv Sonnet 4.6