クライアントサーバシステム(クラサバ、C/Sシステム)は、処理を頼む側の「クライアント」と、頼まれた処理を引き受けて結果を返す「サーバ」に役割を分け、ネットワーク越しに連携させる仕組みです。Webサイトの閲覧もメールの送受信も、この形で動いています。この記事では、HTTPの実際のやり取りを見ながら要求と応答の流れを確認し、2層と3層のクライアントサーバシステムの違いを、動かせるPythonコードと情報処理技術者試験の出題に沿って整理します。
まとめ:クライアントサーバシステムの要点
- クライアントが要求(リクエスト)を送り、サーバが処理して応答(レスポンス)を返す分業の仕組み。
- 「クライアント」「サーバ」は機械の種類ではなく、その通信での役割の名前。同じプログラムが、ある接続ではサーバ、別の接続ではクライアントになる。
- 2層はクライアントがデータベースに直接つなぐ構成、3層はプレゼンテーション層・ファンクション層・データベースアクセス層に分け、業務処理を中間のサーバに集める構成。
- Webシステムも原理的にはクライアントサーバ型。狭義の「クラサバ」は、専用のクライアントソフトを配る方式を指してWebシステムと区別する。
- 身近な例はWeb閲覧、メール、ファイル共有、DNS、スマホアプリとAPI。P2Pは、サービスを提供するサーバを置かず、端末同士が互いにサービスを提供し合う構成。
以下、通信の流れ、2層と3層の構成、ほかの方式との違い、採用の判断基準の順に説明します。
クライアントサーバシステムの仕組みと通信の流れ
要求と応答の流れ(HTTPの実例)
クライアントサーバシステムの基本動作は、クライアントが要求を送り、サーバが応答を返す往復です。Webの通信規格であるHTTPの仕様書 RFC 9110 は、第3.3節で「HTTP is a client/server protocol」と書き、クライアントを「1つ以上のHTTP要求を送るために接続を確立するプログラム」、サーバを「接続を受け付け、HTTP応答を返して要求に応えるプログラム」と定義しています。
実際のやり取りは curl -v で見られます。> で始まる行がクライアントの要求、< で始まる行がサーバの応答です(表示例。応答ヘッダーは取得した時点の内容で、一部を抜粋しています)。
$ curl -sv -o /dev/null https://example.com/
> GET / HTTP/2
> Host: example.com
> User-Agent: curl/8.7.1
> Accept: */*
>
< HTTP/2 200
< content-type: text/html
< server: cloudflare
< allow: GET, HEAD
クライアントは「このページをください(GET)」と要求し、サーバは状態コード200(成功)とHTMLを返しています。RFC 9110 はHTTPを「stateless(状態を持たない)」プロトコルと定め、各要求はそれだけで意味が通じるように作られています。ログイン状態の維持にCookieやトークンを別途使うのはこのためです。
クライアントとサーバの役割の違い
クライアントは自分から接続して要求を出す側、サーバは接続を待ち受けて要求に応える側です。ブラウザや業務アプリのように、利用者の操作を受け取って結果を画面に表示するプログラムがクライアントになるのが典型ですが、画面を持つことが条件ではありません。
| 項目 | クライアント | サーバ |
|---|---|---|
| 通信の始め方 | 自分から接続して要求する | 接続を待ち受けて応える |
| 典型的な処理 | 画面表示・入力チェック | 認証・業務処理・データ管理 |
| 台数の関係 | 多数 | 少数(冗長化で複数台) |
| 例 | ブラウザ・メールソフト・アプリ | Webサーバ・メールサーバ・DBサーバ |
注意したいのは、この区別が機械の種類ではなく役割だという点です。RFC 9110 は「The same program might act as a client on some connections and a server on others.」と明記しています。たとえばWebアプリケーションサーバは、ブラウザから見ればサーバですが、データベースに問い合わせるときはクライアントです。この見方を押さえると、後で説明する3層構成が「クライアントサーバの関係が2段つながったもの」だと理解できます。役割が画面の有無と一致しない例もあり、X Window Systemでは利用者の手元で画面・キーボード・マウスを管理するプログラムが「X server」、そこに描画を依頼するアプリが「X client」です。X.Orgの公式ガイドも、この呼び方は紛らわしいと注意しています。サーバという言葉そのものの意味や種類はサーバーとは何か、役割・種類とクライアントとの違いで扱っています。
複数のクライアントを同時にさばく仕組み
サーバは多数のクライアントから同時に要求を受けます。並行処理の実装方法の一つが、接続ごとにスレッドやプロセスを分ける方式です。次のPythonコードは、標準ライブラリだけで1台のサーバと2回の要求を再現したものです。socketserver の ThreadingTCPServer が、要求ごとに新しいスレッドを立てて処理します。なお、この例のクライアントは応答を受け取ってから次の要求を送る順次送信で、別スレッドが割り当てられる様子を見るためのものです。
import socket
import socketserver
import threading
class Handler(socketserver.StreamRequestHandler):
def handle(self):
line = self.rfile.readline().decode().strip()
reply = f"OK {line.upper()} (thread={threading.current_thread().name})"
self.wfile.write((reply + "\n").encode())
server = socketserver.ThreadingTCPServer(("127.0.0.1", 0), Handler)
host, port = server.server_address
threading.Thread(target=server.serve_forever, daemon=True).start()
def client(msg):
with socket.create_connection((host, port)) as s:
s.sendall((msg + "\n").encode())
return s.makefile().readline().strip()
for m in ["hello", "order 42"]:
print("client:", m, "| server:", client(m))
server.shutdown()
server.server_close()
client: hello | server: OK HELLO (thread=Thread-2 (process_request_thread))
client: order 42 | server: OK ORDER 42 (thread=Thread-3 (process_request_thread))
上はPython 3.10での出力例です。3.10からスレッド名に対象の関数名が括弧付きで付くようになったため、3.9では Thread-2 のように括弧が付きません。要求ごとに別のスレッドが応答しているのが分かります。スレッドは1本ごとにメモリを使うので、同時接続が増えるほど資源の消費も増えます。大量の接続を受けるサーバは、1本のスレッドで多数の接続を切り替える非同期I/Oや、ロードバランサーで複数台に振り分ける構成を組み合わせます。
クライアントサーバシステムの身近な具体例
日常的に使うサービスの多くはクライアントサーバ型です。どの組み合わせでも、クライアントとサーバが同じ約束事(プロトコル)で話すことで成り立っています。
| 場面 | クライアント | サーバ | 主なプロトコル |
|---|---|---|---|
| Webサイトの閲覧 | Webブラウザ | Webサーバ | HTTP(RFC 9110) |
| メールの送信 | メールソフト | SMTPサーバ | SMTP(RFC 5321) |
| メールの受信 | メールソフト | IMAP・POP3サーバ | IMAP4rev2(RFC 9051)・POP3(RFC 1939) |
| 名前解決 | OSのリゾルバ | DNSサーバ | DNS |
| 社内のファイル共有 | PCのエクスプローラー | ファイルサーバ | SMB |
| スマホアプリ | アプリ本体 | APIサーバ | HTTPS |
| 業務システム | 業務アプリ | DBサーバ | DBごとの独自プロトコル |
Webページを1枚開くだけでも、ブラウザはまずDNSサーバにドメイン名のIPアドレスを問い合わせ、次にWebサーバへHTTPで要求します。1つの操作の裏で、複数のクライアントサーバ関係が順番に動いています。
2層と3層のクライアントサーバシステムの違い
2層クライアントサーバシステムの構成と弱点
2層クライアントサーバシステムは、利用者のPCに入れた業務アプリがデータベースサーバへ直接接続する構成です。画面と業務処理の多くはクライアント側、データはサーバ側に置きます。間に別のサーバを挟まないので、構築するサーバと通信の経路が少なく済むのが利点です。
弱点は台数が増えたときに表れます。まず、業務ルールをクライアントのアプリに書いている場合、ルールを変えるたびに全PCのアプリを入れ替える必要があります。次に、データベースへの接続が端末の数だけ張られます。PostgreSQLの公式ドキュメントは同時接続数の上限 max_connections を「typically 100 connections」と説明し(接続設定のページ)、接続ごとにバックエンドプロセスを1つ起動する「process per user」モデルだと書いています。100接続のうち既定で3接続(superuser_reserved_connections)は管理者用に確保されるため、一般の接続に使えるのは97です。端末1台が接続を1本だけ使う単純な構成でも、100台規模で上限に届きます。さらに、データベースの接続情報が各PCに置かれるため、端末1台の侵害がデータベースへの直接アクセスにつながります。
2層でも業務処理をサーバ側に寄せる方法はあります。データベースの中に処理をまとめておくストアドプロシージャです。業務ルールをストアドプロシージャに置けば、ルール変更はデータベース側の更新で済み、クライアントとサーバの往復も1回にまとまってネットワークの負荷が下がります。IPAの基本情報技術者試験シラバスも、2層・3層のクライアントサーバシステムと並べて「データベースに対するストアドプロシージャなど関連技術の特徴」を学習項目に挙げています。
3層クライアントサーバシステムの3つの層
3層クライアントサーバシステムは、2層の弱点を解消するために、業務処理を中間のサーバへ切り出した構成です。基本情報技術者試験シラバス Ver.9.2は、クライアントサーバシステムの用語例として「プレゼンテーション層,ファンクション層,データベースアクセス層」を挙げています。クライアントに近い順に、この並びで積み重なります。
| 層 | 別名 | 担当 | 置き場所の例 |
|---|---|---|---|
| プレゼンテーション層 | UI層 | 画面表示・入力受付 | ブラウザ・専用アプリ |
| ファンクション層 | アプリケーション層 | 業務処理・認証 | アプリケーションサーバ |
| データベースアクセス層 | データ層 | データの読み書き | DBサーバ |
要点は、プレゼンテーション層がデータベースに直接触れないことです。画面側はファンクション層に依頼するだけで、SQLもデータベースの場所も知りません。業務ルールがファンクション層の1か所に集まるので、サーバ内で完結するルール変更なら端末側の入れ替えが要りません(画面の項目やAPIの形が変わる場合はクライアントの更新も必要です)。データベースへの接続も、アプリケーションサーバが接続プールとしてまとめて管理できます。
次のコードは、3つの層の役割分担を1つのPythonファイルで再現したものです。実際にはサーバを分けて配置しますが、ここではDBサーバの代わりにメモリ上のSQLiteを使う模擬例で、接続プールやDBサーバとの通信は再現していません。在庫が足りなければ注文を断るという業務ルールは、中間のファンクション層だけに書いてあります。数量の検証や未登録商品の扱いは省いた教材用のコードです。
import json
import sqlite3
import threading
import urllib.error
import urllib.request
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
# データベースアクセス層:在庫テーブル
db = sqlite3.connect(":memory:", check_same_thread=False)
db.execute("CREATE TABLE stock (item TEXT PRIMARY KEY, qty INTEGER)")
db.execute("INSERT INTO stock VALUES ('pen', 3)")
lock = threading.Lock()
# ファンクション層:在庫が足りなければ断るというルールはここだけに置く
class Api(BaseHTTPRequestHandler):
def do_POST(self):
req = json.loads(self.rfile.read(int(self.headers["Content-Length"])))
with lock:
(qty,) = db.execute("SELECT qty FROM stock WHERE item=?", (req["item"],)).fetchone()
if qty < req["qty"]:
status, body = 409, {"error": "在庫不足", "stock": qty}
else:
db.execute("UPDATE stock SET qty=qty-? WHERE item=?", (req["qty"], req["item"]))
status, body = 200, {"ok": True, "stock": qty - req["qty"]}
data = json.dumps(body, ensure_ascii=False).encode()
self.send_response(status)
self.send_header("Content-Type", "application/json; charset=utf-8")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
def log_message(self, *args):
pass
srv = ThreadingHTTPServer(("127.0.0.1", 0), Api)
threading.Thread(target=srv.serve_forever, daemon=True).start()
# プレゼンテーション層:DBの場所もSQLも知らず、HTTPで注文を送るだけ
def order(item, qty):
url = f"http://127.0.0.1:{srv.server_port}/orders"
req = urllib.request.Request(url, json.dumps({"item": item, "qty": qty}).encode(),
{"Content-Type": "application/json"})
try:
with urllib.request.urlopen(req) as r:
return r.status, json.loads(r.read())
except urllib.error.HTTPError as e:
return e.code, json.loads(e.read())
print(order("pen", 2))
print(order("pen", 2))
srv.shutdown()
srv.server_close()
db.close()
(200, {'ok': True, 'stock': 1})
(409, {'error': '在庫不足', 'stock': 1})
1回目の注文は通り、在庫が1個になった後の2回目はファンクション層が409(競合)で断っています。クライアント側のコードには在庫のチェックが一行もありません。2層で同じことをクライアントのアプリに書くと、在庫チェックのロジックが全端末に埋め込まれ、ルール変更のたびに配布が必要になります(ストアドプロシージャに置けばこの配布は避けられます)。
層ごとの責務分担や、外部システムとの連携を担う層まで含めた設計は3層アーキテクチャとインテグレーション層の解説で、構成を図に起こす方法はシステム構成図の種類と書き方で扱っています。
2層と3層の比較
| 比較軸 | 2層 | 3層 |
|---|---|---|
| 業務処理の置き場所 | クライアントかDB | アプリケーションサーバ |
| DBへの接続 | 端末ごとに直接 | 中間サーバがまとめる |
| 業務ルール変更時 | アプリ内なら全端末へ再配布 | サーバ内で完結すればサーバ更新のみ |
| DBの接続情報 | 各端末に置く | サーバ内に閉じる |
| 構築の手間 | 少ない | 中間層の分だけ増える |
| 向く規模 | 数十台規模のLAN | 利用者数が読めない規模 |
利用者が増えても業務ルールとDB接続を中間層でまとめて管理できることが、3層を選ぶ理由です。逆に、利用者が固定の少人数で、LANの外に出ない小さな社内ツールなら、中間層を持たない2層も検討できます。
Webシステム・メインフレーム・P2Pとの違い
Webシステムとの違い
Webシステムも、ブラウザがクライアント、Webサーバがサーバという意味では原理的にクライアントサーバ型です。それでも両者が区別されるのは、狭い意味の「クライアントサーバシステム(クラサバ)」が、業務ごとに作った専用のクライアントソフトを各PCに入れる方式を指すからです。
基本情報技術者試験 平成24年度秋期 午前問13は、3層クライアントサーバシステムで作ったWebシステムの特徴として「業務処理はサーバ側で実行し,クライアントソフトはHTMLの記述に従って,その結果を画面に表示する」を正解(ウ)にしています(IPA公表の解答例で確認)。専用アプリを端末ごとに配らなくても、ネットワークでサーバに届く端末ならブラウザから使える点が、Webシステムとの違いです。IPAのシラバスも、クライアントサーバシステムとWebシステムを別の学習項目として並べています。
| 比較軸 | 狭義のクラサバ | Webシステム |
|---|---|---|
| クライアント | 専用アプリ | Webブラウザ |
| 配布・更新 | 各端末へインストール | サーバ側の更新で済む |
| 主な通信 | 社内LAN・独自プロトコル | HTTPS |
| オフライン動作 | アプリの作り次第 | Service Worker等で実装 |
| 端末機器の制御 | しやすい | ブラウザの権限内に限られる |
Webシステムの開発工程や言語の選び方はWebシステム開発の仕組みと流れにまとめています。
メインフレーム(集中処理)との違い
クライアントサーバシステムの前は、大型の汎用機(メインフレーム)に処理を集め、計算能力を持たない端末から使う集中処理が主流でした。JPNICの「インターネット用語1分解説」は、1970年代頃までは少数のコンピュータに計算機資源を集中させて端末から利用していたこと、コンピュータの低価格化とネットワークの普及で分業のほうが安く済む場合が増え、クライアントサーバシステムが1980年代以降に普及したことを説明しています。
端末とクライアントの違いは、自分で処理できるかどうかです。端末は入出力しかできませんが、クライアントはそれ自体がコンピュータなので、受け取ったデータの加工や画面の組み立てを手元で行えます。銀行の勘定系のように、今もメインフレームで処理の中核を担う分野もあり、その場合も周辺はクライアントサーバ型やWebで組まれています。勘定系の構造は勘定系システムの三層構造と情報系との違いで扱っています。
P2P(ピアツーピア)との違い
P2Pは、対等な立場の端末同士が直接データをやり取りする方式です。クライアントサーバシステムでは、特定のサービスをサーバ役のコンピュータがまとめて提供し、利用者の端末はそれを受け取ります(サーバ役のプログラムが別の接続でクライアントになることはあります)。P2Pでは、同じサービスについて各端末が受ける側と提供する側の両方を兼ねます。JPNICも、互いにサービスを提供し合う形態をピアツーピアと呼ぶと説明しています。
サーバが1か所にある構成は、管理や認証を集中できる一方、サーバが止まれば全体が止まります。P2Pは特定の1台に依存しないため障害に強い反面、データの一貫性や利用者の管理は難しくなります。実際のサービスでは、利用者の接続相手を探す部分だけをサーバに任せ、映像や音声は端末同士で直接送る、といった組み合わせも使われます。
クライアントサーバシステムの採用判断
一元管理の利点とサーバ依存の弱点
利点は、データをサーバに集めて一元管理できることです。サーバ上のデータなら、バックアップやアクセス権の管理をサーバ側でまとめて行えます。業務処理もサーバに置く構成(3層やストアドプロシージャ)なら、ルールの変更もサーバ側で済み、処理の重い部分を寄せた分だけ端末の性能要件も下がります。
デメリットは、サーバとネットワークに依存することです。サーバが1台だけなら、そこが単一障害点になり、止まれば全利用者が使えなくなります。利用者が増えればサーバの増強やロードバランサーによる負荷分散、DBの冗長化が要り、サービスの稼働時間に合わせた運用監視の手間とコストもかかります。狭義のクラサバ(専用アプリ)の場合は、これに端末ごとのアプリ配布と更新の管理が加わります。
専用クライアントを今あえて選ぶ条件
この記事の判断としては、新しく業務システムを作るならブラウザをクライアントにするWebシステムを第一候補にし、サーバ側は中間層を持つ3層で組むことを勧めます。端末ごとの配布作業が無く、社外や在宅からも同じ画面を使えるからです。専用クライアントを選ぶのは、次のようにWebでは要件を満たせないときに限ってよいでしょう。
- レジ、計測器、医療機器、バーコードリーダーなど、端末につないだ機器をブラウザの権限を超えて制御する必要がある
- 通信が切れても大量のデータ入力を続け、復旧後にまとめて送る必要があり、ブラウザのオフライン機能(Service Worker等)では保存容量や端末管理の要件を満たせない
- CADや映像編集のように、描画や計算を端末のGPU・CPUで処理しないと操作が追いつかない
逆に、利用者の端末の種類や台数が読めない、社外の取引先にも使わせる、更新を頻繁に出す、という条件があるのに、全端末へ確実に配布・更新する仕組み(資産管理ツールやアプリストア)を持てないなら、上の要件があっても専用クライアントは見直したほうがよいでしょう。配布と更新の手間が、利用者の増加に比例して膨らむためです。なお、スマホアプリとAPIサーバの組み合わせは、専用クライアントを配る点で狭義のクラサバに近い構成ですが、アプリストアの自動更新が配布の手間を肩代わりしています。
よくある質問
クラサバとは何の略ですか?
クライアントサーバ(client-server)の略で、クライアントサーバシステムやクライアントサーバ方式を指します。C/Sシステムとも書きます。業務の現場では、Webシステムと対比して「専用アプリを配る方式」の意味で使われることが多い言葉です。
クライアントサーバシステムの身近な例は何ですか?
Webサイトの閲覧(ブラウザとWebサーバ)、メールの送受信(メールソフトとメールサーバ)、社内のファイル共有(PCとファイルサーバ)、スマホアプリとAPIサーバなどです。
2層と3層のクライアントサーバシステムの違いは何ですか?
クライアントとデータベースの間に、業務処理を受け持つ中間のサーバがあるかどうかの違いです。2層はクライアントがDBへ直接つなぎ、業務処理はクライアントのアプリかDB(ストアドプロシージャ)に置きます。3層は業務処理をアプリケーションサーバに集め、クライアントはDBに触れません。
Webシステムはクライアントサーバシステムに含まれますか?
原理的には含まれます。ブラウザがクライアント、Webサーバがサーバだからです。ただし業務システムの文脈では、専用アプリを使う方式を「クラサバ」、ブラウザを使う方式を「Webシステム」と呼び分けます。
クライアントサーバシステムとP2Pの違いは何ですか?
サービスの提供元が集まっているかどうかです。クライアントサーバシステムでは、サーバ役のコンピュータがサービスをまとめて提供します。P2Pでは各端末が利用側と提供側を兼ねます。