プロセス間ファイル記述子の受け渡し
こんにちわ!DQNです!
thundering herd 問題の解決法のひとつ、子プロセスにファイル記述子を送りつけるって奴を実験。
Python C拡張のサンプルにもなってるけどDQNなので難しいことはまったくできませんよ!
sendmsg.c
#include <Python.h> #include <sys/socket.h> static PyObject * sendmsg_sendmsg(PyObject *self, PyObject *args) { int conn, fd, res; char dummy; char buf[CMSG_SPACE(sizeof(int))]; struct msghdr msg = {0}; struct iovec iov; struct cmsghdr *cmsg; if(!PyArg_ParseTuple(args, "ii", &conn, &fd)) return NULL; iov.iov_base = &dummy; iov.iov_len = 1; msg.msg_control = buf; msg.msg_controllen = sizeof(buf); msg.msg_iov = &iov; msg.msg_iovlen = 1; cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); msg.msg_controllen = cmsg->cmsg_len; *(int*)CMSG_DATA(cmsg) = fd; Py_BEGIN_ALLOW_THREADS res = sendmsg(conn, &msg, 0); Py_END_ALLOW_THREADS if (res < 0) return PyErr_SetFromErrno(PyExc_OSError); Py_RETURN_NONE; } static PyObject * sendmsg_recvmsg(PyObject *self, PyObject *args) { int conn, fd, res; char dummy; char buf[CMSG_SPACE(sizeof(int))]; struct msghdr msg = {0}; struct iovec iov; struct cmsghdr *cmsg; if (!PyArg_ParseTuple(args, "i", &conn)) return NULL; iov.iov_base = &dummy; iov.iov_len = 1; msg.msg_control = buf; msg.msg_controllen = sizeof(buf); msg.msg_iov = &iov; msg.msg_iovlen = 1; cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); msg.msg_controllen = cmsg->cmsg_len; Py_BEGIN_ALLOW_THREADS res = recvmsg(conn, &msg, 0); Py_END_ALLOW_THREADS if (res < 0) return PyErr_SetFromErrno(PyExc_OSError); fd = *(int*)CMSG_DATA(cmsg); return Py_BuildValue("i", fd); } static PyMethodDef SendmsgMethods[] = { {"sendmsg", sendmsg_sendmsg, METH_VARARGS, ""}, {"recvmsg", sendmsg_recvmsg, METH_VARARGS, ""}, {NULL, NULL, 0, NULL} /* Sentinel */ }; PyMODINIT_FUNC init_sendmsg(void) { PyObject *m; m = Py_InitModule("_sendmsg", SendmsgMethods); }
setup.py
from distutils.core import setup, Extension module1 = Extension('_sendmsg', sources = ['sendmsg.c']) setup( name='sendmsg', version='0.1', description='This is a DQN package', ext_modules = [module1])
test.py
import _sendmsg import os import socket import time class Test(object): def __init__(self): self.is_child = None def fork(self): pid = os.fork() if pid > 0: self.is_child = 0 else: self.is_child = 1 def ready(self): if self.is_child: self._child_ready() else: self._parent_ready() def _parent_ready(self): file = open('test.txt', 'r') fd = file.fileno() print "parent %s" % os.fstat(fd) time.sleep(2) sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.connect('test.sock') _sendmsg.sendmsg(sock.fileno(), fd) def _child_ready(self): sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.bind('test.sock') sock.listen(1) conn, addr = sock.accept() fd = _sendmsg.recvmsg(conn.fileno()) print "child %s" % os.fstat(fd) file = os.fdopen(fd, 'r') print file.readline() if __name__ == '__main__': t = Test() t.fork() t.ready()
なんかforkとか久々に使った気もする。
あってるのかわかんないな、このコード。だってDQNだし。
parent (33188, 24590563L, 234881026L, 1, 501, 20, 23L, 1221661223, 1221660036, 1221660036)
child (33188, 24590563L, 234881026L, 1, 501, 20, 23L, 1221661223, 1221660036, 1221660036)
statの結果は同じっぽい。
でもファイルエントリテーブルが共有されるはずだけどカレントファイルポジションの位置がおかしかった。
送信する前にseekとかでちょっとでもずらすと受けとる側ではカレントファイルポジションが末尾になってた。
fdを渡たして読むとまた違うのかも知れない。
よーわからんな、だってDQNだから。
Python C拡張、IPCなど以下の2冊がとても参考になります。
- 作者: アレックスマーテリ,Alex Martelli,クイープ
- 出版社/メーカー: オライリージャパン
- 発売日: 2004/03/01
- メディア: 単行本
- 購入: 2人 クリック: 158回
- この商品を含むブログ (25件) を見る
- 作者: W.リチャードスティーヴンス,W.Richard Stevens,大木敦雄
- 出版社/メーカー: ピアソンエデュケーション
- 発売日: 2000/12
- メディア: 単行本
- 購入: 8人 クリック: 103回
- この商品を含むブログ (40件) を見る