rust - 使用 Elixir 通过 Ports 与 Rust 对话,我哪里出错了?

标签 rust port elixir native

我正在编写教程,因为我在任何地方都找不到通过端口在 Elixir 和 Rust 之间进行通信的简单示例。

我可以让 RuSTLer 工作,但那是 NIF,不是 Port。

我的代码中遗漏了一些基本的东西。我不确定我是否遗漏了 stdio 中的一些基本内容,或者是否还有其他内容,但我已经尝试了很多不同的东西。

可以让端口通信与 Rust 中的一个非常基本的程序一起工作:

use std::env;

fn main() {
    println!("hello world!");
}

我可以通过运行此端口将它拉入我的 iex -S 混合:

defmodule PortExample do

  def test() do
    port = Port.open({:spawn_executable, "_build/dev/rustler_crates/portexample/debug/portexample"}, [:binary])
    Port.info(port)
    port
end

这是 iex 的样子:

Interactive Elixir (1.4.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> PortExample.test()
#Port<0.9420>
iex(2)> flush()
{#Port<0.9420>, {:data, "hello world!\n"}}
:ok
iex(3)> 

我可以使用陶瓷库调用来做同样的事情:

  alias Porcelain.Result
  def porcelain() do
    result = Porcelain.exec("_build/dev/rustler_crates/portexample/debug/portexample",["hello", "world"])
    IO.inspect result.out
  end

对应的iex:

iex(3)> PortExample.porcelain()
"hello world!\n"
"hello world!\n"
iex(4)> 

但是,一旦我开始使用具有某种形式的输入/输出的 Rust 库,事情就开始变得糟糕了。

例如,Rust 代码:

use std::io::{self, Write, Read};

fn main() {
    let mut input = String::new();
    let mut output = String::new();
    for i in 0..2 {
        match io::stdin().read_line(&mut input) {
            Ok(n) => {
                println!("input: {}", input.trim());
                io::stdout().flush();
            }
            Err(error) => println!("error: {}", error),
        }
    }
}

我可以让它在命令行中编译和运行:

hello
input: hello
world
input: hello
world

但是,当我从 Elixir 端口调用它时:

iex(12)> port = PortExample.test()
#Port<0.8779>
iex(13)> Port.command(port, "hello")
true
iex(14)> Port.command(port, "world")
true
iex(15)> Port.command(port, "!")    
true
iex(16)> Port.command(port, "more")
true
iex(17)> flush()
:ok
iex(18)> Port.info(port)
[name: '_build/dev/rustler_crates/portexample/debug/portexample',
 links: [#PID<0.271.0>], id: 4697, connected: #PID<0.271.0>, input: 0,
 output: 15, os_pid: 21523]

我根本没有得到任何数据!但是,Port.info(port) 调用显示它收到了 15 个字节。它只是没有将任何返回的东西发布到端口。我一直在尝试阅读其他代码,我认为我正在做足够相似的事情,它应该可以工作,但事实并非如此。

我想:也许缓冲区没有被刷新?所以我用 Rust 刷新缓冲区。 我想:也许循环挂了,所以我将它限制为只有几次通过。 当我尝试通过 porcelain 调用运行相同的代码时,它挂起了。

最佳答案

你正在读取 Rust 代码中的一行输入,它将读取到 \r\n\n,但你没有发送来自 Elixir 的换行符。如果您更改所有 Port.command 调用以在消息后添加 \n,它会起作用:

iex(1)> port = Port.open({:spawn_executable, "a"}, [:binary])
#Port<0.1229>
iex(2)> Port.command(port, "hello")
true
iex(3)> flush()
:ok
iex(4)> Port.command(port, "hello\n")
true
iex(5)> flush()
{#Port<0.1229>, {:data, "input: hellohello\n"}}
:ok

关于rust - 使用 Elixir 通过 Ports 与 Rust 对话,我哪里出错了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44050019/

相关文章:

logging - 有没有办法在我的应用程序的生产构建中静态禁用 Rust 日志记录?

apache - 从 XAMPP 运行 apache 服务时出错

erlang - Erlang 接收表达式到底是如何工作的?

rust - 具有借阅特征的逆泛型约束

由于库不纯导致的 Debian 9.2 错误

rust - 如何根据 Peekable::peek 的结果调用 Peekable::next?

c++ - 使用 C++ 和 Boost(或不使用?)检查是否正在使用特定端口?

sockets - 检查端口是否在 ANT 中打开

elixir - 从 Enum 中获取被拒绝/未过滤的元素

postgresql - 使用 Ecto 查询对 jsonb 列中的字段求和