socketのbind
code:socket-bind.py
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('127.0.0.1', 1234))
s.listen()
while True:
conn, addr = s.accept()
with conn:
data = b''
while True:
chunk = conn.recv(4096) # 受信データが4096byteちょうどだと問題になる
data += chunk
if len(chunk) < 4096:
break
conn.sendall(data)
リファレンス
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
アドレスファミリー、ソケットタイプ、プロトコル番号を指定して新しいソケットを作成します。アドレスファミリーには AF_INET (デフォルト値)、 AF_INET6 、 AF_UNIX 、 AF_CAN 、または AF_RDS を指定します。ソケットタイプには SOCK_STREAM (デフォルト値)、 SOCK_DGRAM 、 SOCK_RAW 、または他の SOCK_ 定数を指定します。
socket.bind(address)
ソケットを address にbindします。bind済みのソケットを再バインドする事はできません。(address のフォーマットはアドレスファミリによって異なります -- 前述。)
socket.listen([backlog])
サーバーを有効にして、接続を受け付けるようにします。システムが新しい接続を拒否するまでに許可する未受付の接続の数を指定します。指定しない場合、デフォルトの妥当な値が選択されます。
socket.accept()
接続を受け付けます。ソケットはアドレスにbind済みで、listen中である必要があります。戻り値は (conn, address) のペアで、 conn は接続を通じてデータの送受信を行うための 新しい ソケットオブジェクト、 address は接続先でソケットにbindしているアドレスを示します。
コード解説
socket.socket(socket.AF_INET, socket.SOCK_STREAM) で利用する socketの種別を指定 AF_INET: IPv4通信
SOCK_STREAM: TCP通信
s.bind() で 127.0.0.1 (ローカルループバックインターフェース) の 1234 ポートにbindしている
s.listen() TBD
s.accept() で接続を待ち受ける。相手が接続するまで関数呼び出しがブロックされる
conn.recv(4096) で、送られてくる受信データを最大4096 byte読み出す
実際の受信データが4096 byte未満なら、続きのデータはない
4096 byte以上なら、もう一度conn.recvで続きを受信する必要がある
(問題: 受信データが4096byteちょうどだと、whileの2週目でconn.recv()から読み出せずに固まる)
受け取ったデータ data をそのまま送り返している
いわゆるエコーサーバー
1回データを返す毎にコネクションを切っている
with conn ブロックを抜けるとコネクションを切断する
実行
code:cosole
$ python3 socket-bind.py
別コンソールで実行
code:telnet(console)
$ telnet 127.0.0.1 1234
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
I'm Your Father
I'm Your Father
Connection closed by foreign host.
参考
ソケットはそこかしこで使われているが、最大級に誤解されている技術でもある。この文書はソケットの全体像を俯瞰しており、チュートリアルとしてはあまり役に立たない。実際に動くモノを完成させるには、他にもやらなければいけないことがあるからだ。この文書はソケットの微妙なところ (たくさんある) まではカバーしていないが、恥ずかしくない使い方ができるようになる程度の情報は得られるはずだ。