ソケットプログラミングとは

ソケット(Socket)

実行中のプログラム間でデータの送受信を行うための標準的なプログラミングインターフェース (API) の一つ.

TCP/IP アプリケーションを作成するための抽象化されたインターフェース

ref. ソケット (BSD) - Wikipedia

通信端点, 通信の出入り口になるようなドアの概念.

EndPoints

端末.一意に定まる通信先.

Socket は IP Address と PortNo.をつかって, 通信先のソケットを特定する. ネットワークに接続されたパソコンや PDA, 携帯電話などのネットワーク端末の総称. エンドボイントに Socket がバインドされる.

Loopbacks

IP アドレスは必ずしもリモートホストと関連付けられている必要はない. とくに開発環境では, ローカルな IP アドレスが役に立つ.

自端末に対して通信することを LoopBack という. LoopBack で指定するアドレスを Loopback Address という.

  • ハードウェアと関係ない, 論理的なインタフェース.
  • Linux では, localhost と言われている. IP は 127.0.0.1

ref. ループバックとは 〔 ローカルループバック 〕

Ports

ポートフォワーディング

ローカルコンピュータの特定のポートに送られてきたデータを別に用意した通信経路を用いてリモートコンピュータの特定ポートに送信すること.

ref. ポートフォワーディングとは 【 port forwarding 】

たとえば, Windows ファイルサーバに,SSH 経由で (CIFS, port 445/tcp で) アクセスする (した).

Stream

データの入力または出力の機能を提供する抽象データ型. メッセージの境界という境界がない. TCP/IP プロトコルはストリームベースの設計.

ref. ストリーム (プログラミング) - Wikipedia

Blocking/Non-Blocking

ブロッキング

送受信の完了を待ってから他の処理を開始する通信方法.

require 'socket'
server = TCPServer.new (2803)
while client = server.accept
  input = client.readline
  client.write "You said: #{input}"
  client.close
end

ノン・ブロッキング

データの送受信を行う際に, 送受信の完了を待たず他の処理を開始する通信方法.

ref. ノンブロッキング通信とは 〔 ノンブロッキングモード 〕

require 'socket'
server = TCPServer.new (2803)
loop do
  Thread.new (server.accept){ |client|
    input = client.readline
    client.write "You said: #{input}"
    client.close
  }
end

Example Ruby

Server Lifecycle

  1. create ソケットの生成
  2. bind
    • ソケットを利用する Port にバインド.
      • User でバインドする Port は 1025-48999
    • ソケットが通信を許可する IP を指定.
      • 0.0.0.0: すべて許可
      • 127.0.0.1: 自端末のみ許可
      • xxx.xxx.xxx.xxx: ある端末のみ許可
  3. listen 通信先ソケットからの通信をまつ
  4. accept 通信先ソケットからの通信を受け取り, 通信路 をそのつど生成 (connection)
  5. close 通信元ソケットの消滅.
# coding: utf-8
require 'socket'
 
# 1. create
server = Socket.new (:INET, :STREAM)
 
# 2. bind
addr = Socket.pack_sockaddr_in (4481, "0.0.0.0")
server.bind (addr)
 
# 3. listen
server.listen (5)
 
# 4. accept
loop do
  connection, _ = server.accept
 
  ## send message from client.
  # ehco "Hello" | nc localhost 4481
  p connection
 
  # it should be closed each connection
  connection.close
end
 
# 5. close
server.close

TCPServer

Ruby では, 以下のような糖衣構文がある.

ref. class TCPServer

server = TCPServer.new (4481)
# =>
# server = Socket.new (:INET, :STREAM)
# addr = Socket.pack_sockaddr_in (4481, "0.0.0.0")
# server.bind (addr)
# server.listen (5)

Client LifeCycle

  1. create ソケットの生成

(2. bind )

  1. connect サーバと接続
  2. close ソケットの破棄
require 'socket'
 
# 1. create
socket = Socket.new (:INET, :STREAM)
 
# 3. connect
remote_addr = Socket.pack_sockaddr_in (80, 'google.com')
socket.connect (remote_addr)
 
# 4. close
socket.close

TCPSocket

Ruby では, 以下のような糖衣構文がある.

ref. class TCPSocket

socket = TCPSocket.new ('google.com', 80)
# =>
# socket = Socket.new (:INET, :STREAM)
# remote_addr = Socket.pack_sockaddr_in (80, 'google.com')
# socket.connect (remote_addr)

Simple Read

以下の例では, 永遠にサーバは Read を待ち続けて, その先が進まない.

require 'socket'
 
Socket.tcp_server_loop (4481) do |connection|
  puts connection.read
  connection.close
end

Socket は指定されたデータ長のデータが到着するまで待ち続ける. デッドロックを回避するためには,

  • Client 側で データの最後で EOF を送信する.(EOF event)
  • Server 側で一度に読み込むデータ長を小さくする. (partial read)

Client のソケットが close メソッドを実行すると, その延長で EOF が通知される.

🔖通信タイムアウト

Socket Timeout/Connection Timeout/Connection Request Timeout

JavaのApache HttpClentの使用だがいろんな言語実装で登場するのでまとめておく. 設定可能な3つの属性の意味はそれぞれ以下の通り.

  • socket timeout: ソケット通信のスタートから終了まで.
  • connection timeout: クライアントからサーバへの接続確立(3way-shake)まで
  • connection-request-timeout: 接続確立後からレスポンスが返るまで.

ref. JavaのHttpClientにおける3つのTimeoutの違いに関して - Qiita

エラーが発生したときの障害解析で大事なのは, 自分が悪いのかサーバが悪いのかという問題.

Connection Timeoutはサーバへの通信が届いてないのでサーバは悪くない. Socket Timeoutはサーバからの通信か切れたのでサーバが悪いかも.

connection timeoutは3の倍数

TCPの仕様で3秒ごとに状況確認をするようで, 3の倍数で設定するのがよいとのこと.

【Python】requestsを使うときは必ずtimeoutを設定するべき | Cosnomi Blog

Broken pipe

よくssh接続とかで見かけるやつ. プログラムを動かしていて通信エラーでもでる.

packet_write_wait: Connection to port 22: Broken pipe

Broken pipeと出力される原因はクライアントからサーバ(ssh接続先)に対して一定時間無操作ためタイムアウトにより切断されたと思われます.

これはクライアント側が被疑箇所の可能性. サーバからの応答完了を待たずに接続終了. しかし応答を待っているのが期待時間外あればサーバが被疑箇所の可能性もある. いずれにしろリトライによって救済を試みることがよい.

TOCs

References