この記事は?
ソケットについて調べた際の走り書きです。
調べた動機
- HTTP - (ソケット?) - TCP - IP - …
- MySQL の
/tmp/mysql.sock
もソケット?
OSI参照モデル > 例 > 層別の例 - Wikipedia より
内容
- ソケット: ネットワーク通信に用いるファイルディスクリプタ (file descriptor)
- UNIX 系 OS (Linux など) では入出力はすべてバイト列として扱われる。その入出力ではバイト列のことをストリーム (stream) と呼ぶ
- ファイルディスクリプタ: ストリームを区別する識別子 (整数)
- 0: 標準入力
- 1: 標準出力
- 2: 標準エラー出力
- そのほかのストリームはオープンされるたびに小さい番号から順に使われクローズされると同じ番号が再利用される
- ファイルディスクリプタが対応しているストリームの接続先がローカルのファイルやネットワーク経由の接続というように種類が異なっていても、全く同じように入出力できる
- つまりストリームを透過的に扱える
- ソケットではファイルに対する操作と同様の操作でネットワーク通信を進められる
プロトコルファミリー ソケットタイプ |
SOCK_STREAM | SOCK_DGRAM | 特定方法 | 通信 |
---|---|---|---|---|
AF_INET AF_INET6 |
TCP | UDP | IP アドレス ポート番号 |
ホスト間 |
AF_UNIX | UNIX ドメインソケット | UNIX ドメインソケット | ファイル名 | プロセス間 |
- ソケットの種類
- INET ドメインソケットと UNIX ドメインソケット
- 特定方法
- TCP: 5 タプル (プロトコル、送信側 IP、送信側ポート、受信側 IP、受信側ポート)
- UNIX ドメインソケット:
- MySQL サーバーがローカルクライアントと通信するために使用する UNIX ソケットファイルのデフォルトの場所は /tmp/mysql.sock である
- プロトコルファミリー
- AF_INET: IPv4 インターネットプロトコル
- AF_INET6: IPv6 インターネットプロトコル
- AF_UNIX: ローカル通信
- ソケットタイプ
- SOCK_STREAM: 順序性と信頼性があり、双方向の接続されたバイトストリームを提供する
- 帯域外データ転送メカニズムもサポートする
- SOCK_DGRAM: データグラムをサポートする
- データグラム (datagram): 配送成功・到達時間・到達順序がネットワークサービスによって保証されることがないパケット交換網における基本転送単位
- SOCK_STREAM: 順序性と信頼性があり、双方向の接続されたバイトストリームを提供する
- ソケットによる通信を行う際に使用するシステムコール
- システムコール: アプリケーションと Linux カーネルとの間の基本的なインターフェース。
- socket(), bind(), listen(), accept(), read(), write(), close()
- ソケットはファイルディスクリプタなので、通常のファイルに対する場合と同様に read(), write() が使える
Chapter 4. Elementary TCP Sockets - Shichao's Notes より
Ruby でソケットを扱ってみる。
require 'socket'
# TCP Server
server = TCPServer.new(12_345)
loop do
# TCPServer#accept
# クライアントからの接続要求を受け付け、接続した TCPSocket のインスタンスを返す。
socket = server.accept
socket.print(Time.now.strftime('%Y/%m/%d (%a) %H:%M:%S'))
socket.close
end
require 'socket'
# TCP Client
TCPSocket.open('localhost', 12_345).read
#=> "2024/11/16 (Sat) 21:30:31"
# サーバを閉じた後。
TCPSocket.open('localhost', 12_345).read
# Connection refused - connect(2) for "localhost" port 12345 (Errno::ECONNREFUSED)
$ lsof -i:12345
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ruby 20178 quanon 8u IPv4 0x9db00af21468648e 0t0 TCP localhost:61265->localhost:italk (CLOSE_WAIT)
ruby 20482 quanon 10u IPv6 0x2c83fda6bc3c44f 0t0 TCP *:italk (LISTEN)
require 'socket'
# TCP Server
server = UNIXServer.new('/tmp/sock')
loop do
socket = server.accept
socket.print(Time.now.strftime('%Y/%m/%d (%a) %H:%M:%S'))
socket.close
end
require 'socket'
# TCP Client
UNIXSocket.open('/tmp/sock').read
#=> "2024/11/16 (Sat) 21:31:40"
# サーバを閉じた後。
UNIXSocket.open('/tmp/sock').read
# Connection refused - connect(2) for /tmp/sock (Errno::ECONNREFUSED)
参考
記事
- まつもと直伝 プログラミングのオキテ 第16回 ネットワーク・プログラミング(ソケット編)
- ファイル記述子 - Wikipedia
- ソケット (BSD) - Wikipedia
- macos - Get list of open files (descriptors) in OS X - Stack Overflow
- 調べなきゃ寝れない!と調べたら余計に寝れなくなったソケットの話 - Qiita
- Man page of SOCKET
- Chapter 4. Elementary TCP Sockets - Shichao's Notes
- RubyでいろいろなSocket作って遊んでみた。 - Qiita
- Jep-380: unix domain socket channels – Inside.java
- fork 後に子プロセスにパイプを渡す