`
arksea
  • 浏览: 64422 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

Windows平台下erlang的port进程关闭标准输入输出的方法

阅读更多

为了避免与port进程的通信受一些printf调试信息的影响,通常都要关闭或者替换标准输入输出。

Unix平台下,open_port只要指定nouse_stdio参数就可以让port进程使用fd 3、4作为通信信道,

而在Windows平台下并没有所谓的3、4 fd可用,调用fdopen(3,“rb”)将会出错,这时可以使用

dup和dup2手动进行替换,例子如下:


port测试进程C代码

 

#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <io.h>
#include <fcntl.h>
#include <windows.h>

int main(int argc, char* argv[])
{
    //复制stdio fd,之后我们将使用复制的句柄与Erlang通信
    FILE* f0 = fdopen(dup(0),"rb");
    FILE* f1 = fdopen(dup(1),"wb");

    //Windows下默认为Text模式,按需要设置为BINARY模式,
    //否则\n将会被替换为\r\n,这通常不是我们想要的
    _setmode (_fileno(f0), _O_BINARY);
    _setmode (_fileno(f1), _O_BINARY);

    //用一个临时文件替换stdio,并关闭之
    FILE* ftmp = tmpfile();
    dup2(fileno(ftmp), 0);
    dup2(fileno(ftmp), 1);
    fclose(stdin);
    fclose(stdout);
    fclose(ftmp);
    //测试一些输出
    fwrite("hello",1,5,f1);
    fputc(' ',f1);
    fflush(f1);
    printf("world");
    fflush(stdout);
    std::cout << "!!!!!\n";
    std::cout.flush();
    Sleep(5000);

	return 0;
}

 

 

测试用erlang代码:

 

-module(test).
-compile(export_all).

start() ->
  P = open_port({spawn, "./Debug/teststdio.exe"},[binary]),
  loop(P).
  
loop(P) ->
  receive
    {P, {data, Data}} ->
 	io:format("~p~n",[Data]),
 	loop(P)
  after 3000 ->
    timeout
  end.

 

 

测试结果:

 

1、替换stdio后:

Eshell V5.7.5  (abort with ^G)
1> c(test.erl).
{ok,test}
2> test:start().
<<"hello ">>
timeout
3>

 

2、如果没有替换stdio,将会收到

test:start().
<<"hello ">>
<<"world">>
<<"!!!!!\r\n">>
timeout

 

我们调用第三方库时很难确认是否会有stdio输出,这种方式很好的避免了printf信息对port通信的影响

 

 注意没有替换stdio部分的输出,stdin和stdout没有指定BINARY模式,\n被替换成\r\n了,

 再看看前面dup2部分的调用,虽然指定了"rb"和"wb",但这样是无效的,必须手动调用setmode进行设置才会有效

 

 最后说说windows下使用异步stdio的注意点,需要2个设置:

1、在open_port中指定overlapped_io参数

2、用_get_osfhandle函数得到替换后的io的HANDLE,以供ReadFile和WriteFile操作:

 

    HANDLE hin = (HANDLE)_get_osfhandle(_fileno(f0));
    HANDLE hout= (HANDLE)_get_osfhandle(_fileno(f1));

 

 在C程序里使用异步io虽然麻烦,但有时候却是必须的。比如windows系统下通过port访问串行口时,如果不使用overlapped模式,读取串口与读取stdio是不能同时进行的。

分享到:
评论
2 楼 mryufeng 2010-08-24  
星爷威武!
1 楼 imyer 2010-06-28  
感谢,感谢。
最近正因为“\n将会被替换为\r\n”
测试了很多方法。
_setmode (_fileno(f1), _O_BINARY); 
后,传输没问题,特别是二进制文件。

相关推荐

    erlang -c语言程序接口.pdf

    - `#include &lt;io.h&gt;` 包含了从标准输入输出设备读写数据的函数。 - `_read` 和 `_write` 函数用于读写数据。 - `_read` 的第一个参数表示读取的方向(0表示输入,1表示输出)。 - `_write` 的第一个参数表示写入的...

    Erlang中执行linux命令的两种方法

    总结来说,`os:cmd/1`适合执行简单命令并获取标准输出,而`erlang:open_port/2`则适用于更复杂的场景,如需要错误信息、退出状态码或者控制进程交互。选择哪种方法取决于你的具体需求和对性能的影响。

    erlang api 最新资源

    io_server是一个处理输入输出请求的进程,负责执行客户端请求的任务,比如读写设备。客户端是任何希望从设备读取或向设备写入数据的Erlang进程。Erlang的标准库STDLIB定义了I/O协议的当前实现。I/O协议历史悠久,...

    erlexec:从ErlangOTP执行和控制OS进程

    5. **I/O重定向**:`erlexec`支持标准输入、输出和错误流的重定向,可以将进程的输出捕获到Erlang进程中处理。 三、使用示例 在Erlang代码中,我们可以使用`open_port/2`函数调用`erlexec`来执行命令。例如,执行`...

    exos:Exos是一个简单的Port Wrapper:一个GenServer,它将强制转换和调用转发到链接的Port

    在 Elixir 中,Port 通常需要手动管理输入输出的二进制数据,这可能会变得复杂且容易出错。Exos 将这个过程封装在一个 GenServer 实例中,它会处理数据的转换和通信,使得与外部程序的交互更为简洁。通过 Exos,你...

    放逐:替代运行外部程序的端口。 它提供背压,无阻塞io,并解决与端口相关的问题

    "放逐"(Exile)是一个基于Erlang和Elixir编写的库,它提供了一种替代方法来运行外部程序,同时解决了与传统端口相关的诸多问题。Exile的设计目标是提供背压(back-pressure)支持,实现无阻塞I/O操作,从而提高系统...

Global site tag (gtag.js) - Google Analytics