it

TCPのセッションとは?コネクションとの違いも!(通信セッション:状態管理:タイムアウト:切断:established stateなど)

当サイトでは記事内に広告を含みます

TCPのセッションとは?コネクションとの違いも!(通信セッション:状態管理:タイムアウト:切断:established stateなど)

ネットワーク通信を学んでいると、「セッション」や「コネクション」という言葉に頻繁に出会うでしょう。これらは似ているようで、実は意味が異なる概念です。特にTCPのセッションは、Webアプリケーションやサーバー管理の現場でも非常に重要なテーマとなっています。

本記事では、TCPセッションとは何か、コネクションとの違い、状態管理やタイムアウト、切断の仕組み、established stateなど、通信の根幹をなす概念をわかりやすく解説していきます。エンジニアとしてのスキルをより深めたい方はぜひ最後までご覧ください。

TCPセッションとは「通信の開始から終了までの一連の流れ」のこと

それではまず、TCPセッションの本質的な意味について解説していきます。

TCPセッションとは、クライアントとサーバーが通信を開始し、データをやり取りして、最終的に通信を終了するまでの一連のやり取り全体を指す概念です。単なるパケットの送受信ではなく、「誰が・誰に・どのような状態で通信しているか」という文脈を持つ点が大きな特徴といえるでしょう。

TCPは「Transmission Control Protocol」の略で、インターネットにおける信頼性の高い通信を実現するプロトコルです。UDPと異なり、データの到達保証や順序制御を行うため、Webブラウジング・メール・ファイル転送など多くの場面で活用されています。

セッションが持つ「状態」という概念

TCPセッションの重要な特徴の一つが、状態管理(ステート管理)です。TCPでは通信の進行に応じて、接続がどのフェーズにあるかを追跡しています。この状態は「TCPステートマシン」とも呼ばれ、各段階が明確に定義されています。

代表的な状態には以下のようなものがあります。

状態名 説明
CLOSED 接続が存在しない初期状態
LISTEN サーバーが接続要求を待ち受けている状態
SYN_SENT クライアントがSYNを送信し、応答を待っている状態
SYN_RECEIVED サーバーがSYNを受け取り、SYN+ACKを送信した状態
ESTABLISHED コネクションが確立し、データ通信が可能な状態
FIN_WAIT_1 接続終了要求(FIN)を送信した状態
TIME_WAIT 接続終了後、一定時間待機している状態

このように、TCPセッションは単純な「接続中」「切断中」ではなく、細かな状態の遷移によって管理されています。

セッションIDと識別の仕組み

TCPセッションはネットワーク上で一意に識別される必要があります。その識別には「4タプル」と呼ばれる4つの情報が使用されます。具体的には「送信元IPアドレス」「送信元ポート番号」「宛先IPアドレス」「宛先ポート番号」の組み合わせです。

この4タプルが同じである通信は同一のセッションとして扱われ、異なる場合は別のセッションとなります。これにより、1台のサーバーが同時に複数のクライアントと通信を行っていても、それぞれを正確に識別して管理できるわけです。

アプリケーション層のセッションとの関係

TCPセッションはOSI参照モデルのトランスポート層(第4層)における概念です。一方、HTTPセッションやSSLセッションはアプリケーション層(第7層)の概念となります。

たとえばWebサイトにログインした状態を維持する「ログインセッション」はHTTPレベルの話であり、TCP層のセッションとは別の管理が行われています。TCPセッションが切れてもHTTPセッション情報(クッキーやトークン)が残っていれば再接続後も認証状態を引き継ぐことができるでしょう。

TCPセッションとコネクションの違いを整理する

続いては、混同されがちな「セッション」と「コネクション」の違いを確認していきます。

「セッション」と「コネクション」は日本語でも英語でもほぼ同義に使われることがありますが、厳密には異なるニュアンスを持っています。コネクション(connection)はTCP層において物理的・論理的な通信路が確立されている状態そのものを指し、セッション(session)はその通信路を使った一連のやり取り全体を指す概念として区別されることが多いです。

コネクションの確立:3ウェイハンドシェイク

TCPコネクションは「3ウェイハンドシェイク」という手順で確立されます。この仕組みを理解することがセッションの本質的な理解につながるでしょう。

3ウェイハンドシェイクの流れは以下のとおりです。


# 3ウェイハンドシェイクの流れ
ステップ1: クライアント → サーバー
SYN(同期要求)パケットを送信
seq=100(シーケンス番号)
ステップ2: サーバー → クライアント
SYN+ACK(同期応答+確認応答)を返す
seq=300, ack=101
ステップ3: クライアント → サーバー
ACK(確認応答)を送信
ack=301
出力結果:コネクション確立 → ESTABLISHED状態に移行

この3ステップが完了することで、双方向の通信路が確立され、ESTABLISHED状態となります。ここからが実際のデータ送受信フェーズ、つまりセッションの本体といえる部分です。

セッション vs コネクションの対比表

両者の違いをより明確にするために、以下の表で整理してみましょう。

項目 コネクション セッション
レイヤー トランスポート層(L4) L4〜アプリケーション層
意味合い 通信路の確立状態 通信の一連の流れ全体
確立方法 3ウェイハンドシェイク コネクション確立後に開始
終了方法 4ウェイFINハンドシェイク 論理的な終了条件で完了
状態管理 OS・カーネルが管理 アプリケーションも関与

コネクションはあくまでも「道路」であり、セッションはその道路を使った「旅のルートと目的地」に相当するイメージでしょう。

複数セッションと接続の再利用(Keep-Alive)

HTTP/1.1以降では「Keep-Alive」という仕組みにより、1つのTCPコネクション上で複数のHTTPリクエスト(セッション)を処理できるようになっています。毎回コネクションを張り直すオーバーヘッドを減らすため、パフォーマンス向上に大きく貢献しています。

一方、HTTP/2では多重化(マルチプレキシング)がさらに進化し、1つのTCPコネクション上で複数のリクエストを並列処理できるようになりました。コネクションとセッションの関係はプロトコルの世代によっても変化していることがわかるでしょう。

ESTABLISHED状態・タイムアウト・切断の仕組みを深掘りする

続いては、TCPセッションのライフサイクルの中でも特に重要な「ESTABLISHED状態」「タイムアウト」「切断」について確認していきます。

ESTABLISHED stateとは何か

ESTABLISHED state(確立状態)は、TCPセッションの中で最も重要な状態です。3ウェイハンドシェイクが完了し、双方向にデータを自由に送受信できるフェーズを指します。

ESTABLISHED stateはTCPセッションが「生きている」状態を意味します。この状態が続く間、クライアントとサーバーは自由にデータを送受信できます。サーバーの負荷状況や同時接続数を確認する際、ESTABLISHED状態のセッション数は非常に重要な指標となります。

Linuxサーバーでは以下のコマンドで現在のESTABLISHED状態の接続を確認できます。


# ESTABLISHED状態のTCPセッションを確認するコマンド
ss -tn state established
または
netstat -an | grep ESTABLISHED
出力結果:
Recv-Q Send-Q Local Address           Foreign Address
0      0      192.168.1.10:443        203.0.113.55:52341
0      0      192.168.1.10:80         203.0.113.88:49200

このように、現在進行中のセッションをリアルタイムで把握することがサーバー管理の基本となるでしょう。

TCPタイムアウトの種類と役割

タイムアウトはTCPセッションの安定運用において欠かせない仕組みです。通信が途中で途絶えた場合に、リソースを無駄に保持し続けないよう、一定時間後に自動的にセッションを終了させる役割を担っています。

主なタイムアウトの種類を以下に整理します。

タイムアウト種別 概要 一般的な設定値
接続タイムアウト コネクション確立までの待機時間 数秒〜数十秒
アイドルタイムアウト データ送受信がない状態の許容時間 数分〜数時間
TIME_WAITタイムアウト 切断後の待機時間(2MSL) 約60〜120秒
Keep-Aliveタイムアウト アイドル接続維持のための確認間隔 環境により異なる

特にTIME_WAITタイムアウトは、切断後も一定時間セッション情報を保持する仕組みです。これは遅延パケットによる誤作動を防ぐための安全弁として機能しています。

TCPセッションの切断:4ウェイFINハンドシェイク

TCPセッションの正常な切断には「4ウェイFINハンドシェイク」が使用されます。3ウェイで始まり、4ウェイで終わるのがTCPの特徴です。


# 4ウェイFINハンドシェイクの流れ
ステップ1: クライアント → サーバー
FIN(終了要求)を送信
クライアント側はFIN_WAIT_1状態へ
ステップ2: サーバー → クライアント
ACK(確認応答)を返す
クライアントはFIN_WAIT_2状態へ
ステップ3: サーバー → クライアント
サーバーもFIN(終了要求)を送信
サーバーはLAST_ACK状態へ
ステップ4: クライアント → サーバー
ACK(確認応答)を返す
クライアントはTIME_WAIT状態へ → CLOSED
出力結果:双方のTCPセッション終了、CLOSEDへ移行

なお、異常切断の場合はRSTパケット(リセット)が送られ、即座にセッションが破棄されます。これは通常の終了フローとは異なるため、ログ上でRSTが多発している場合は何らかの問題が発生している可能性があるでしょう。

Pythonを使ったTCPセッション制御のサンプルコード

続いては、実際のPythonコードでTCPセッションの動きを確認していきます。

TCPの概念は抽象的になりがちですが、実際にコードを動かすことでより深い理解が得られます。Pythonのsocketライブラリを使えば、TCPセッションの確立から切断までを手を動かして体験できるでしょう。

TCPサーバー側のセッション受け入れコード

まずはサーバー側のサンプルコードです。接続を受け付け、クライアントからのメッセージを受信します。


import socket
サーバーのホストとポートを設定
HOST = '127.0.0.1'
PORT = 65432
TCPソケットを作成(IPv4、TCPを指定)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket:
# ポートの再利用を許可(TIME_WAIT対策)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# バインドしてLISTEN状態に移行
server_socket.bind((HOST, PORT))
server_socket.listen()
print(f"サーバー起動: {HOST}:{PORT} でLISTEN中")

# クライアントの接続を待ち受け(ESTABLISHED状態へ)
conn, addr = server_socket.accept()

with conn:
    print(f"接続確立 (ESTABLISHED): クライアントアドレス = {addr}")
    
    # データ受信ループ
    while True:
        data = conn.recv(1024)
        if not data:
            break
        print(f"受信データ: {data.decode()}")
        # エコーバック
        conn.sendall(data)
    
print("セッション終了: コネクションがCLOSEDになりました")
出力結果:
サーバー起動: 127.0.0.1:65432 でLISTEN中
接続確立 (ESTABLISHED): クライアントアドレス = ('127.0.0.1', 52341)
受信データ: ドラゴンフルーツ
セッション終了: コネクションがCLOSEDになりました

TCPクライアント側のセッション開始コード

次にクライアント側のコードです。サーバーへ接続し、データを送信してセッションを終了します。


import socket
接続先サーバーの情報
HOST = '127.0.0.1'
PORT = 65432
TCPソケットを作成
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client_socket:
# 3ウェイハンドシェイクを実行してESTABLISHED状態へ
client_socket.connect((HOST, PORT))
print(f"セッション確立 (ESTABLISHED): {HOST}:{PORT} に接続しました")
# データ送信(アボカドとサーモンの在庫情報を模擬)
messages = ["アボカド:在庫50個", "サーモン:在庫20kg", "ドラゴンフルーツ:在庫5個"]

for msg in messages:
    client_socket.sendall(msg.encode())
    data = client_socket.recv(1024)
    print(f"送信: {msg} / エコー受信: {data.decode()}")

# withブロック終了時にFINハンドシェイクが実行される
print("セッション終了処理中(4ウェイFINハンドシェイク)")
出力結果:
セッション確立 (ESTABLISHED): 127.0.0.1:65432 に接続しました
送信: アボカド:在庫50個 / エコー受信: アボカド:在庫50個
送信: サーモン:在庫20kg / エコー受信: サーモン:在庫20kg
送信: ドラゴンフルーツ:在庫5個 / エコー受信: ドラゴンフルーツ:在庫5個
セッション終了処理中(4ウェイFINハンドシェイク)

タイムアウトをコードで制御する方法

実運用ではタイムアウトの設定が非常に重要です。以下はソケットにタイムアウトを設定するサンプルコードです。


import socket
HOST = '127.0.0.1'
PORT = 65432
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
# 接続タイムアウトを5秒に設定
sock.settimeout(5.0)
try:
    # 接続試行(5秒以内に応答がなければTimeoutError)
    sock.connect((HOST, PORT))
    print("接続成功: ESTABLISHEDになりました")
    
    # データ受信のタイムアウトを3秒に設定
    sock.settimeout(3.0)
    
    sock.sendall("キーボード:ワイヤレスモデル".encode())
    
    try:
        response = sock.recv(1024)
        print(f"レスポンス受信: {response.decode()}")
    except socket.timeout:
        # アイドルタイムアウト発生
        print("受信タイムアウト: セッションをクローズします")

except socket.timeout:
    print("接続タイムアウト: サーバーへの接続に失敗しました")
except ConnectionRefusedError:
    print("接続拒否: サーバーがLISTEN状態ではありません")
出力結果:
接続成功: ESTABLISHEDになりました
レスポンス受信: キーボード:ワイヤレスモデル

タイムアウト設定はセッションの安定性とリソース効率の両立に欠かせません。本番環境では用途に応じて適切な値を選ぶことが大切でしょう。

まとめ

本記事では「TCPのセッションとは?コネクションとの違いも!(通信セッション:状態管理:タイムアウト:切断:established stateなど)」というテーマで、TCPセッションの全体像を解説してきました。

TCPセッションとは、通信の開始から終了までの一連の流れ全体を指す概念です。一方、コネクションは通信路そのものを指し、セッションはその上で行われるやり取りという関係にあります。

TCPセッション理解のポイントをまとめると、①セッションは「4タプル」で一意に識別される、②ESTABLISHED stateがデータ通信の中心フェーズ、③切断は4ウェイFINハンドシェイクで行われる、④タイムアウト設定がリソース管理の要となる、この4点が特に重要です。

Pythonのsocketライブラリを使えば、これらの仕組みを実際のコードで体感できます。TCP通信はWebアプリケーション・ネットワーク機器・クラウドインフラなど、あらゆる現代技術の基盤となっています。ぜひ本記事の内容を足がかりに、より深い通信プロトコルの理解へと進んでいただければ幸いです。