从Python 2到3迁移时,文件描述符 /插座处理差异

发布于 2025-02-05 03:52:22 字数 1682 浏览 2 评论 0原文

我正在从Python 2到3迁移一个应用程序。该应用程序涉及一个python脚本,该脚本协调了C应用程序的一些实例。 Python脚本为每个应用程序打开一个套接字,然后将相应的文件描述符传递给C程序。这与Python 2.7中的原始版本一起使用,但与Python 3.6或3.9中断。

我能够找到一个更改:stdinstdoutstderr > info 在这里

要做的是:

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 明确地传递pass_fds = [11],这也无济于事。

如果我运行该应用程序并单独创建套接字,那么它可以正常工作,包括从Python脚本启动的时间。因此,在这一点上,我可以肯定的是,问题与从Python 2到Python 3的一些变化有关。

还有其他变化可能会影响观察到的行为吗?我还能尝试使它起作用?

I'm migrating an application from Python 2 to 3. The app involves in a Python script that orchestrates a few instances of a C app. The python script opens a socket for each app and then passes the corresponding file descriptor to the C program. This works with the original version in Python 2.7 but breaks with Python 3.6 or 3.9.

I was able to find one change: the file descriptors apart from stdin, stdout and stderr are not inherited by the child processes by default (more info here)

What I do is the following:

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

Then I check the corresponding process: either it exists and there is a server waiting for a connection in case of Python 2 or the process is dead in case of Python 3.

I tried to set the file descriptor to be inheritable:

os.get_inheritable(11)                      
# Out[15]: False
os.set_inheritable(11, True)

However that did not help, the app still crashes.

I also tried to explicitly pass pass_fds = [11] to Popen, that also did not help.

If I run the app and let it create the socket on its own then it works fine including when it is started from the Python script. So at this point I'm fairly certain that the problem has to do with some changes from Python 2 to Python 3.

Are there any other changes that could be having an impact on the observed behavior? What else could I try to make it work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

策马西风 2025-02-12 03:52:22

这里的问题似乎是您永远不会在套接字上调用listing()。如果我将您的代码修改为(a)设置sasenitable flag,并且(b)调用listan,以便看起来像这样:

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()

where 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_inherable,代码如您在问题中所描述的失败。

The problem here appears to be that you're never calling listen() on your socket. If I modify your code to both (a) set the inheritable flag, and (b) call listen, so that it looks like this:

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()

Where socklisten is the following simple program that prints out a string on a given file descriptor:

#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);
    }

}

It all works as expected. If I run the Python code, it opens the socket and waits for the child process to exit:

$ python server.py
listening on 51163

If I connect to that port, I see the expected response:

$ nc localhost 51163
This is a test.

If I remove either the call to sock.listen or the call to sock.set_inheritable, the code fails as you describe in your question.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文