首页 > 解决方案 > 如何为 Haxe 中的新进程设置文件描述符以将其与套接字一起使用?

问题描述

我正在将一些代码从 Python 转换为 Haxe,以便我可以针对更多平台。但是我在使用以下代码段时遇到了麻烦。

import socket
from subprocess import Popen

host='127.0.0.1'
port=8080
file='handle.sh'

handler = socket.socket()
handler.bind((host, port))
handler.listen(5)


conn, address = handler.accept() # Wait for something to connect to the socket
proc = Popen(['bash', file], stdout=conn.makefile('wb'), stdin=conn.makefile('rb'))
proc.wait()
conn.shutdown(socket.SHUT_RDWR)
conn.close()

在 Python 中,我可以将 stdin 和 stdout 设置为套接字的相关文件描述符。但是当我调用关机时,所有要发送的数据都在正确的缓冲区中,没有什么能阻止我。

但据我所知,我不能在 Haxe 中执行此操作,因为来自套接字的输入和输出以及来自进程的 stdin 和 stdout 都是只读的。

无论我尝试什么,我似乎都会陷入僵局。目前我正在尝试使用一个线程,但它仍然卡在从套接字读取。

#!/usr/bin/haxe --interp
import sys.net.Host;
import sys.net.Socket;
import sys.io.Process;
import sys.thread.Thread;

class HaxeServer {
    static function main() {
        var socket = new Socket();

        var fname = 'handle.sh';
        var host = '127.0.0.1';
        var port = 8080;

        socket.bind(new Host(host), port);
        socket.listen(5);
        while (true) {
            var conn = socket.accept();
            var proc = new Process('bash', [fname]);
            exchange(conn, proc);
            conn.output.write(proc.stdout.readAll());
            proc.close();
            conn.shutdown(true, true);
            conn.close();
        }
    }
    static function exchange(conn:Socket, proc:Process):Void {
        #if (target.threaded)
        Thread.create(() -> {
            while (true) {
                var drip = conn.input.readByte();
                proc.stdin.writeByte(drip);
            }
        });
        #end
    }
}

编辑 1

尝试使用@YellowAfterlife 发布的答案,我运行了以下代码而不是我的交换函数。

            conn.setBlocking(false);

            Thread.create( () -> {
                trace('--> read');
                while (true) {
                    trace('-1a');
                    var data:Bytes = readAllNonBlocking(conn.input).bytes;
                    trace('-2a');
                    proc.stdin.write(data);
                    trace('-3a');
                    proc.stdin.flush();
                }
            });

            trace('--> write');
            while (true) {
                trace('-1b');
                var data:Bytes = readAllNonBlocking(proc.stdout).bytes;
                trace('-2b');
                conn.output.write(data);
                trace('-3b');
                conn.output.flush();
            }

            trace('Wait');
            trace(proc.exitCode());

但它只是记录并挂起:

HaxeServer.hx:42: --> write
HaxeServer.hx:44: -1b

所以它甚至没有进入线程并且输入仍然阻塞。如果我将两个读写部分都放在线程中,它只会打印“等待”。

标签: pythonhaxe

解决方案


我以前处理过(在桥接不相关网络 API 的项目 - GitHub repo 上)通过将套接字标记为非阻塞并实现读取所有可用数据的自定义函数来读取所有可用数据而不会死锁的问题,如下所示:

public static function readAllNonBlocking(input:Input):{bytes:Bytes,eof:Bool} {
    var total:BytesBuffer = new BytesBuffer();
    var eof = false;
    var len = 0;
    try {
        while (true) {
            total.addByte(input.readByte());
            len += 1;
        }
    } catch (x:Error) {
        switch (x) {
            case Blocked: // OK!
            default: throw x;
        }
    } catch (x:Eof) {
        eof = true;
    }
    
    var bytes:Bytes = total.getBytes();
    if (bytes.length > len) {
        bytes = bytes.sub(0, len);
    }
    
    return { bytes: bytes, eof: eof };
}

您可能还需要.flush()标准输入数据才能真正进入流程。


推荐阅读