17  端口和端口驱动程序

17  端口和端口驱动程序

如何在 互操作性教程 中使用端口和端口驱动程序的示例。有关提到的 BIF 的信息,请参见 ERTS 中的 erlang(3) 手册页。

从 Erlang 的角度来看,端口提供了与外部世界通信的基本机制。它们为外部程序提供了一个面向字节的接口。创建端口后,Erlang 可以通过发送和接收字节列表(包括二进制)与之通信。

创建端口的 Erlang 进程被称为端口所有者或端口的连接进程。所有与端口的通信都必须通过端口所有者进行。如果端口所有者终止,端口也会终止(以及外部程序,如果它编写正确)。

外部程序驻留在另一个操作系统进程中。默认情况下,它从标准输入(文件描述符 0)读取并写入标准输出(文件描述符 1)。外部程序在端口关闭时终止。

可以根据某些原则用 C 编写一个驱动程序,并将其动态链接到 Erlang 运行时系统。链接的驱动程序从 Erlang 编程人员的角度来看就像一个端口,被称为端口驱动程序

警告

错误的端口驱动程序会导致整个 Erlang 运行时系统发生内存泄漏、挂起或崩溃。

有关端口驱动程序的信息,请参见 ERTS 中的 erl_driver(4) 手册页、ERTS 中的 driver_entry(1) 手册页和 Kernel 中的 erl_ddll(3) 手册页。

创建端口

open_port(PortName, PortSettings 打开新 Erlang 端口的结果,返回一个端口标识符 Port。就像 pid 一样,可以向端口标识符发送消息并从中接收消息。端口标识符也可以使用 link/1 链接,或使用 register/2 注册到一个名称下。

表 17.1:   端口创建 BIF

PortName 通常是一个元组 {spawn,Command},其中字符串 Command 是外部程序的名称。外部程序在 Erlang 工作空间之外运行,除非找到一个名为 Command 的端口驱动程序。如果找到 Command,则启动该驱动程序。

PortSettings 是端口设置(选项)的列表。该列表通常至少包含一个元组 {packet,N},它指定在端口和外部程序之间发送的数据前面都有一个 N 字节的长度指示符。N 的有效值为 1、2 或 4。如果要使用二进制而不是字节列表,则必须包含选项 binary

端口所有者 Pid 可以通过发送和接收消息来与端口 Port 通信。(实际上,任何进程都可以向端口发送消息,但必须在消息中标识端口所有者)。

发送到端口的消息是异步传递的。

更改

在 Erlang/OTP 16 之前,发送到端口的消息是同步传递的。

在下表中,Data 必须是 I/O 列表。I/O 列表是一个二进制或一个(可能很深)的二进制或整数列表,范围为 0..255

消息 描述
{Pid,{command,Data}} Data 发送到端口。
{Pid,close} 关闭端口。除非端口已关闭,否则端口在所有缓冲区刷新并端口真正关闭时,将使用 {Port,closed} 进行回复。
{Pid,{connect,NewPid}} Port 的端口所有者设置为 NewPid。除非端口已关闭,否则端口将使用 {Port,connected} 向旧端口所有者进行回复。请注意,旧端口所有者仍然与端口链接,但新端口所有者没有。

表 17.2:   发送到端口的消息

消息 描述
{Port,{data,Data}} 从外部程序接收 Data
{Port,closed} Port ! {Pid,close} 的回复。
{Port,connected} Port ! {Pid,{connect,NewPid}} 的回复。
{'EXIT',Port,Reason} 如果端口由于某种原因终止。

表 17.3:   从端口接收的消息

除了发送和接收消息之外,还可以使用许多 BIF

端口 BIF 描述
port_command(Port,Data) Data 发送到端口。
port_close(Port) 关闭端口。
port_connect(Port,NewPid) Port 的端口所有者设置为 NewPid。旧端口所有者 Pid 仍然与端口链接,如果不需要,则必须调用 unlink(Port)
erlang:port_info(Port,Item) 返回由 Item 指定的信息。
erlang:ports() 返回当前节点上的所有端口列表。

表 17.4:   端口 BIF

一些适用于端口驱动程序的其他 BIF:port_control/3erlang:port_call/3