基本情報技術者試験とは
基本情報技術者試験は、情報処理推進機構(IPA)が実施し、「情報処理の促進に関する法律」に基づき経済産業省が認定する国家試験である。
ITエンジニアとしてキャリアをスタートする方のIT基礎力を問う試験で、「ITエンジニアの登竜門」とも呼ばれる。
「基本情報技術者試験」の試験範囲は、IPAのWebサイトに掲載されているシラバスに明記されている。
それでは、基本情報技術者試験(科目A)のサンプル問題にチャレンジしてみよう。
今回は、解説を読むだけでなく、実際にPCの中でサーバーとクライアントの通信をPythonで再現し、双方が使っているポート番号をコードで確かめるという形で理解を深める。(2026.9.24追記)
なお、この記事で使用するコードは、筆者の学習用リポジトリ pc-labo-fe-exam-python の 06_port_number フォルダにまとめている。
問29
PC とWeb サーバがHTTP で通信している。PC からWeb サーバ宛てのパケットでは,送信元ポート番号はPC 側で割り当てた50001,宛先ポート番号は80 であった。WebサーバからPC への戻りのパケットでのポート番号の組合せはどれか。

出典:基本情報技術者試験 科目A サンプル問題 問29(2022年12月)
正解:ア
ポート番号
TCP/IPのネットワークでは、IPアドレスで通信相手のコンピューターを特定する。そのコンピューター上では、複数のアプリケーションが動作している。ポート番号は、通信相手のコンピューター上で稼働しているアプリケーションを識別する番号である。
0から65,535までのポート番号が割り当てられており、そのうち、0から1,023まではウェルノウンポートと呼ばれ、特定のアプリケーションのために予約されている。
20 FTPデータ転送
21 FTPデータ制御
25 SMTP
53 DNS
80 HTTP
110 POP3
本問では、PCからWebサーバへのパケットでは、送信元ポート番号は50001、宛先ポート番号は80である。
以後、2026.9.24追記
つまり、行きのパケットと戻りのパケットとでは、送信元と宛先が入れ替わるというのが、この問題の核心である。それでは、実際に手元のPCで通信を再現し、割り当てられるポート番号をコードで見てみよう。
Pythonでつくって確かめてみよう
Pythonの標準ライブラリ socket を使うと、サーバーとクライアントの通信を1つのスクリプトの中で再現できる。ここでは、threading モジュールでサーバーを別スレッドとして立ち上げ、クライアントから接続して、双方が実際に使っているポート番号を確認する。
なお、ここでは80番ポートの代わりに、一般的に利用しやすい8080番ポートを使う。
「番号が違うだけで、確認したい仕組みは同じ」という点に注目してほしい。
import socket
import threading
SERVER_PORT = 8080 # 80番の代わりに、特権なしで使えるポートを使う
def run_server(ready_event, result):
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.bind(("localhost", SERVER_PORT))
server_sock.listen(1)
ready_event.set() # 準備完了をクライアントに知らせる
conn, _ = server_sock.accept()
result["server_local"] = conn.getsockname() # サーバー自身のアドレスとポート
result["server_remote"] = conn.getpeername() # 接続してきたクライアントのアドレスとポート
conn.close()
server_sock.close()
def run_client(ready_event, result):
ready_event.wait() # サーバーの準備ができるまで待つ
client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_sock.connect(("localhost", SERVER_PORT))
result["client_local"] = client_sock.getsockname() # クライアント自身のアドレスとポート(OSが自動割り当て)
result["client_remote"] = client_sock.getpeername() # 接続先のサーバーのアドレスとポート
client_sock.close()
def main():
ready_event = threading.Event()
result = {}
server_thread = threading.Thread(target=run_server, args=(ready_event, result))
server_thread.start()
run_client(ready_event, result)
server_thread.join()
print("=== クライアント(PC)側から見た通信 ===")
print(f"送信元(自分のポート、OSが割り当て): {result['client_local']}")
print(f"宛先(サーバーのポート) : {result['client_remote']}")
print()
print("=== サーバー(Webサーバー)側から見た通信 ===")
print(f"自分のポート(=クライアントからの宛先): {result['server_local']}")
print(f"クライアントのポート(=クライアントの送信元): {result['server_remote']}")
print()
print("=== 戻りのパケットで使われるポート番号 ===")
print(f"送信元ポート(サーバー自身): {result['server_local'][1]}")
print(f"宛先ポート(クライアントのポート): {result['server_remote'][1]}")
if __name__ == "__main__":
main()実行結果
=== クライアント(PC)側から見た通信 ===
送信元(自分のポート、OSが割り当て): ('127.0.0.1', 54118)
宛先(サーバーのポート) : ('127.0.0.1', 8080)
=== サーバー(Webサーバー)側から見た通信 ===
自分のポート(=クライアントからの宛先): ('127.0.0.1', 8080)
クライアントのポート(=クライアントの送信元): ('127.0.0.1', 54118)
=== 戻りのパケットで使われるポート番号 ===
送信元ポート(サーバー自身): 8080
宛先ポート(クライアントのポート): 54118
※ クライアントのポート番号(例では54118)は、実行するたびにOSが自動的に割り当てるため、毎回変わる。設問の「50001」も、これと同じ仕組みでPC側にその都度割り当てられた番号である。
client_sock.getsockname() は、クライアント自身が使っているアドレスとポートを返す。今回はどこにも番号を指定していないのに、OSが自動的に空いているポート(例では54118)を割り当てていることが確認できる。これが設問の「PC側で割り当てた50001」に対応する。
client_sock.getpeername() は、接続先(サーバー)のアドレスとポートを返す。こちらは SERVER_PORT(8080)を明示的に指定して connect() しているので、常に同じ値になる。これが設問の「宛先ポート番号は80」に対応する。
サーバー側では、conn.getsockname()(自分自身のポート=8080)と conn.getpeername()(クライアントのポート=54118)が、クライアント側の値とちょうど入れ替わった形で得られている。
サーバーがPCへ戻りのパケットを送るとき、サーバーは自分のポート(8080)を送信元として、クライアントのポート(54118)を宛先として送る。これは、設問で言えば「送信元ポート番号は80、宛先ポート番号は50001」とまったく同じ構造である。コードの実行結果として、行きと戻りでポート番号の送信元・宛先が入れ替わる様子を、実際の数値で確認できた。
まとめ
- ポート番号は、通信相手のコンピューター上で稼働しているアプリケーションを識別する番号であり、0〜1,023番はウェルノウンポートとして予約されている
- クライアント側のポート番号は、通信のたびにOSが動的に割り当てる。サーバー側のポート番号は、サービスに応じてあらかじめ決められていることが多い(HTTPなら80番など)
- 行きのパケットと戻りのパケットとでは、送信元ポートと宛先ポートが入れ替わる
- Pythonの
socketモジュールで簡単なサーバーとクライアントを動かし、getsockname()/getpeername()を使うことで、この仕組みを実際のポート番号として目で確認できる
参考リポジトリ
この記事で扱ったコードは、以下の筆者のGitHubリポジトリで公開している。





コメント