kenkovlog

けんこふたんっオフィシャユブヨグッ
アンッ!アンッ!アンッ!アンッ!

socket 接続

よく「複数のプロセスで一つのポート番号に接続することは不可能です」という記述がありますが、その実験。

プログラム

サーバ側は

#! /usr/bin/env python
# coding:utf-8

from __future__ import division, print_function
import socket
import datetime
import os
import time

_host = "localhost"
_port = 10000

s = socket.socket()
s.bind((_host, _port))
s.listen(1)
print("original server socket: {}".format(s.getsockname()))
while True:
    soc, addr = s.accept()
    print("created server socket: {}".format(soc.getsockname()))
    # fork
    pid = os.fork()
    if pid == 0:
        # child
        s.close()
        data = "hi, it's {} now".format(datetime.datetime.now())
        soc.send(data)
        time.sleep(60)
        exit(0)
    else:
        # parent
        soc.close()

クライアント側は

#! /usr/bin/env python
# coding:utf-8

from __future__ import division, print_function
import socket

_host = "localhost"
_port = 10000

s = socket.socket()
s.connect((_host, _port))
print("client socket: {}".format(s.getsockname()))

while True:
    data = s.recv(1024)
    if not data:
        break
    else:
        print("from server: {}".format(data)
s.close()

結果

サーバ側

$ python2 server.py
original server socket: ('127.0.0.1', 10000)
created server socket: ('127.0.0.1', 10000)
created server socket: ('127.0.0.1', 10000)

クライアント側

$ python2 client.py
client socket: ('127.0.0.1', 41089)
from server: hi, it's 2013-04-14 09:35:06.625424 now

接続してきた子プロセスは全て同じポート番号で接続している。

複数サーバを起動してみると

二つ目以降のサーバでは

$ python2 server.py
Traceback (most recent call last):
  File "server.py", line 14, in <module>
    s.bind((_host, _port))
  File "/usr/lib/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 98] Address already in us

となり、接続できない。

つまり

accept は新しいファイルディスクリプタを返すが、それは同じポート番号につながっている。 平行サーバでaccept したファイルディスクリプタをfork して子プロセスが通信する場合でも、 その子プロセスは同じポート番号(ここではポート10000) で接続して通信している。したがって、同じポート番号で 複数のプロセスが(fork されたものだが) 通信していることになる。

結果

よく「複数のプロセスで一つのポート番号に接続することは不可能です」という記述がありますが、 あれは「bind してできたファイルディスクリプタを通して」という意味で不可能という話です。 今回のようにaccept して出来たファイルディスクリプタを使って接続するのであれば複数 プロセスでの接続も可能です。

そもそもaccept で返されるファイルディスクリプタはこのようなことを可能にするためにあると思う。

けんこふたん