我正在將一個應用程式從 Python 2 遷移到 3。該應用程式涉及一個 Python 腳本,該腳本編排了一個 C 應用程式的幾個實體。python 腳本為每個應用程式打開一個套接字,然后將相應的檔案描述符傳遞給 C 程式。這適用于 Python 2.7 中的原始版本,但與 Python 3.6 或 3.9 不同。
我能夠找到一個變化:檔案描述符除了stdin,stdout并且stderr默認情況下不被子行程繼承(更多資訊在這里)
我要做的是:
import socket
import os
import subprocess
sock = socket.socket()
sock.bind(('10.80.100.32',0))
sock
# Out[6]: <socket.socket fd=11, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('10.80.100.32', 36737)>
env = os.environ.copy()
env["LD_LIBRARY_PATH"] = env["LD_LIBRARY_PATH"] ":%s" % os.getcwd()
p = subprocess.Popen(["./app", "--sockfd", "11"], close_fds = False, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p.pid
# Out[10]: 393727
然后我檢查相應的行程:在 Python 2 的情況下它存在并且有一個服務器在等待連接,或者在 Python 3 的情況下行程已死。
我試圖將檔案描述符設定為可繼承:
os.get_inheritable(11)
# Out[15]: False
os.set_inheritable(11, True)
然而這并沒有幫助,應用程式仍然崩潰。
我也嘗試明確傳遞pass_fds = [11]給Popen,這也沒有幫助。
如果我運行應用程式并讓它自己創建套接字,那么它可以正常作業,包括從 Python 腳本啟動時。所以在這一點上,我相當肯定這個問題與從 Python 2 到 Python 3 的一些變化有關。
是否有任何其他變化可能對觀察到的行為產生影響?我還能嘗試什么讓它發揮作用?
uj5u.com熱心網友回復:
這里的問題似乎是你從來沒有呼叫listen()你的套接字。如果我將您的代碼修改為(a)設定inheritable標志和(b)呼叫listen,則它看起來像這樣:
import socket
import os
import subprocess
sock = socket.socket()
sock.set_inheritable(True)
sock.bind(("0.0.0.0", 0))
sock.listen(5)
print("listening on", sock.getsockname()[1])
env = os.environ.copy()
p = subprocess.Popen(
["./socklisten", "{}".format(sock.fileno())],
close_fds=False,
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
p.wait()
socklisten以下在給定檔案描述符上列印字串的簡單程式在哪里:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/wait.h>
int main(int argc, char **argv) {
int sock;
if (argc <= 1) {
fprintf(stderr, "missing socket\n");
exit(1);
}
sock = atoi(argv[1]);
if (sock == 0) {
fprintf(stderr, "invalid socket number\n");
exit(1);
}
while (1) {
int client;
char msg[100];
struct sockaddr_in clientaddr;
socklen_t clientlen = sizeof(struct sockaddr_in);
if (-1 == (client = accept(sock, (struct sockaddr *)&clientaddr, &clientlen))) {
perror("accept");
exit(1);
}
sprintf(msg, "This is a test.\r\n");
write(client, msg, strlen(msg) 1);
close(client);
}
}
這一切都按預期作業。如果我運行 Python 代碼,它會打開套接字并等待子行程退出:
$ python server.py
listening on 51163
如果我連接到該埠,我會看到預期的回應:
$ nc localhost 51163
This is a test.
如果我洗掉對 的呼叫sock.listen或對 的呼叫sock.set_inheritable,則代碼將按照您在問題中的描述失敗。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/488797.html
