Unix Domain SocketでXML-RPC通信

プロセス管理ツールの supervisor のソースコードを読んでいると、サーバー(supervisord)とクライアント(supervisorctl)が XML-RPC を INET ドメインソケットではなく UNIX ドメインソケットで通信していることに気づいた。
ソースコードを読んで Python での実装を確認してみた。

supervisor 起動後の状態

supervisord デーモン起動後 Unix ドメインソケットでサーバーが LISTEN されていることを確認。

$ netstat -l --protocol=unix
Active UNIX domain sockets (only servers)
Proto RefCnt Flags       Type       State         I-Node   Path
unix  2      [ ACC ]     STREAM     LISTENING     5828     @/com/ubuntu/upstart
unix  2      [ ACC ]     STREAM     LISTENING     7020     /var/run/dbus/system_bus_socket
unix  2      [ ACC ]     SEQPACKET  LISTENING     5957     @/org/kernel/udev/udevd
unix  2      [ ACC ]     STREAM     LISTENING     37510    /tmp/supervisor.sock.14587

クライアントプログラム

クライアントの XML-RPC over UNIX ドメインソケットは supervisor/xmlrpc.py で実装されている。そこから supervisor モジュールへの依存など不要なものを取っ払ったのが以下。

# Based On supervisor/xmlrpc.py
import httplib
import socket
import xmlrpclib

class UnixStreamHTTPConnection(httplib.HTTPConnection):
    def connect(self):
        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        self.sock.connect(self.socketfile)

class SupervisorTransport(xmlrpclib.Transport):
    def __init__(self, username=None, password=None, serverurl=None):
        conn = UnixStreamHTTPConnection('localhost')
        conn.socketfile = serverurl
        self.connection = conn
        self.headers = {
            "User-Agent"   : 'Dummy',
            "Content-Type" : "text/xml",
            "Accept"       : "text/xml"
        }

    def request(self, host, handler, request_body, verbose=0):
        self.headers["Content-Length"] = str(len(request_body))
        self.connection.request('POST', handler, request_body, self.headers)
        r = self.connection.getresponse()
        data = r.read()
        return data

def test_call_transport_directly():
    server = SupervisorTransport('/tmp/supervisor.sock')
    handler = '/RPC2'
    data = xmlrpclib.dumps((), 'supervisor.getAPIVersion')
    print server.request(handler, data)

def test():
    proxy = SupervisorTransport(serverurl='/tmp/supervisor.sock')
    server = xmlrpclib.Server('http://127.0.0.1', transport=proxy)
    print server.supervisor.getState()

if __name__ == '__main__':
    test()
    test_call_transport_directly()

XML-RPC サーバーを指定はするが、実際の通信は Transport を介して UNIX ドメインソケットに接続し、データのリクエスト/レスポンスも同ソケット経由で行うようにする。
あとは Unix ドメインソケットのインターフェースを HTTP に合わせてやればOK。

xmlrpclib.Transport の使い方の勉強になる。

サーバプログラム
サーバも UNIX ドメインソケットに対応しようとすると、次の Twisted-Python のメーリングリストにもあるように、ソケットファイルも URL スキームもパスを スラッシュ(/)で区切っているため、かなりグダグダな実装になる。

[Twisted-Python] XML-RPC over Unix Sockets?
http://twistedmatrix.com/pipermail/twisted-python/2009-July/019915.html

自分の能力ではコンパクトに実装できないので、実装は保留。

Advertisements
Tagged with: ,
Posted in middleware

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archives
  • RT @__apf__: How to write a research paper: a guide for software engineers & practitioners. docs.google.com/presentation/d… /cc @inwyrd 4 months ago
  • RT @HayatoChiba: 昔、自然と対話しながら数学に打ち込んだら何かを悟れるのではと思いたち、専門書1つだけ持ってパワースポットで名高い奈良の山奥に1週間籠ったことがある。しかし泊まった民宿にドカベンが全巻揃っていたため、水島新司と対話しただけで1週間過ぎた。 それ… 5 months ago
  • RT @googlecloud: Ever wonder what underwater fiber optic internet cables look like? Look no further than this deep dive w/ @NatAndLo: https… 5 months ago
  • @ijin UTC+01:00 な時間帯で生活しています、、、 10 months ago
  • RT @mattcutts: Google's world-class Site Reliability Engineering team wrote a new book: amazon.com/Site-Reliabili… It's about managing produc… 1 year ago
%d bloggers like this: