YStudio Y++

管道类

Y++ / YStudio 开发文档 · 一点滴

Win32 命名管道 / 匿名管道同步读写。声明写「管道类 p」即可。

  • 产品:Y++ / y++
  • IDE:YStudio
  • 示例管道名请用 Ypp…(如 YppDesk、YppDemoPipe)

匿名管道只在本机(同进程,或把句柄交给子进程)。命名管道的短名也在本机;客户端写 \\电脑名\pipe\名字 可以连另一台 Windows 上的服务端。服务端第七参数「拒绝远程」为真时,只接受本机客户端。它走系统的命名管道,不自己占 TCP 端口;公网、浏览器、手机不要用它。

命名管道(推荐跨进程)

服务端:

管道类 srv
如果 (srv.创建服务端("YppDemoPipe") == 假) {
    输出(srv.取错误())
    返回 ()
}
如果 (srv.等待连接(10000) == 假) {
    输出(srv.取错误())
    返回 ()
}
srv.发送("hello from server")
文本 回 = srv.接收(0, 3000)
srv.断开()   ' 可选:再等待下一个客户端
srv.关闭()

多客户(移交已连接端):

管道类 listen
listen.创建服务端("YppDemoPipe", 65536, 假, 8)
当 (真) {
    如果 (listen.等待连接(5000) == 假) {
        继续()
    }
    管道类 peer = listen.移交已连接端()
    如果 (peer.是否已连接() == 假) {
        输出(listen.取错误())
        继续()
    }
    输出("对端 PID=" + 到文本(peer.取对端进程ID()))
    peer.发送("ok")
    peer.关闭()
}
listen.关闭()

客户端:

管道类 cli
如果 (cli.连接("YppDemoPipe", 5000) == 假) {
    输出(cli.取错误())
    返回 ()
}
文本 t = cli.接收(0, 3000)
cli.发送("ack")
cli.关闭()

事务(一次请求-应答):

' 客户端
文本 回 = cli.事务("ping", 256, 3000)

' 服务端需先读请求再发应答(或对端也用事务时注意消息模式)

模拟客户端(仅服务端):

如果 (srv.模拟客户端()) {
    ' 此处以客户端令牌访问文件/注册表等
    srv.还原模拟()
}

安全描述符(SDDL):

' 允许 Everyone 完全访问(示例;生产请收紧)
srv.创建服务端("YppDemoPipe", 65536, 假, 1, 0, "D:(A;;GA;;;WD)")

匿名管道(同进程读写对)

管道类 读端
管道类 写端 = 读端.创建匿名写端()
写端.发送("ping")
文本 t = 读端.接收(0, 1000)
写端.关闭()
读端.关闭()

跨进程匿名端:创建匿名写端(真) 或事后 置可继承(真),再把句柄交给子进程;否则优先命名管道。

交给「进程类」(不必先置可继承,启动时会复制一份可继承句柄):

管道类 父读
管道类 子写 = 父读.创建匿名写端()
进程类 p
p.置标准输出(子写)
如果 (p.启动("cmd.exe", "/c echo hello") == 假) {
    输出(p.取错误())
    返回 ()
}
子写.关闭()
文本 t = 父读.接收(0, 3000)

标准输入同理:置标准输入(子读),父进程向写端 发送,发完 关闭 写端。父端保持不可继承(创建匿名写端() 默认即是)。

枚举与信息

文本 names[] = 枚举管道()

整数 出 = srv.取输出缓冲()
整数 入 = srv.取输入缓冲()
整数 最大 = srv.取最大实例()    ' 255=不限
整数 当前 = srv.取当前实例()
如果 (srv.是否消息模式()) {
    整数 剩余 = srv.取本消息剩余()
}
输出(srv.取客户端用户名())      ' 仅已连接服务端

发送文件(字节流)

先写 8 字节小端长度,再写文件内容。须「消息模式=假」。上限 8GB。已存在的目标文件会被覆盖;失败会删掉未完成文件。

' 发送端
cli.发送文件("C:\\temp\\a.bin")

' 接收端(超时为整次传输总时限)
srv.接收文件("C:\\temp\\a.bin", 30000)

参数约定

项 说明
管道名 短名 "MyPipe" 内部走 \\.\pipe\MyPipe;\\.\pipe\... 与 \\服务器\pipe\... 原样使用。示例名请用 Ypp…,勿写第三方品牌名
消息模式 创建服务端 第三参数:真=消息模式,假=字节流(默认)
最大实例 第四参数:1~254;≤0 表示不限
方向 第五参数:0 双工、1 入站(服务端只读)、2 出站(服务端只写)
安全描述符 第六参数:SDDL 字符串;空=系统默认
拒绝远程 第七参数:真=仅本机客户端可连接
超时 置超时(毫秒) 用于接收、事务、接收文件;0=非阻塞读。连接 的 0 为不等待。发送 默认一直等到写完,第二参数可单独限时
生命周期 拷贝共享同一条管道。离开作用域且没有别的变量共用时关闭句柄并回收会话。关闭 只关句柄,同一变量还可以再创建或连接
文本收发 UTF-8;二进制用 发送字节集 / 接收字节集 / 事务字节集。消息模式读完整一条用 接收整条消息

方法一览

  • 创建服务端 / 等待连接 / 连接 / 断开 / 关闭
  • 移交已连接端(多客户:连接句柄交给新对象,本端继续监听)
  • 创建匿名写端([可继承])
  • 从句柄打开(句柄[, 角色[, 接管]])
  • 是否已打开 / 是否已连接 / 是否服务端 / 重置
  • 置超时 / 取超时 / 取可读字节数
  • 冲刷 / 清空缓冲([清接收[, 冲刷写出]])
  • 置可继承 / 取可继承
  • 发送([超时]) / 发送字节集([超时]) / 接收 / 接收字节集
  • 接收整条消息 / 接收整条消息字节集(消息模式,读完整一条)
  • 窥探 / 窥探字节集(不取走)
  • 事务 / 事务字节集(命名管双工且消息模式;匿名/单向不支持)
  • 模拟客户端 / 还原模拟 / 是否在模拟
  • 取管道名 / 取错误 / 取句柄 / 取对端进程ID / 取对端会话ID
  • 是否消息模式 / 取输出缓冲 / 取输入缓冲 / 取最大实例 / 取当前实例
  • 取本消息剩余 / 取客户端用户名
  • 发送文件([块大小[, 超时]]) / 接收文件(字节流,长度前缀)
  • 枚举管道()(自由命令,也可 p.枚举管道())

自由命令:创建管道()(一般不必调,直接声明类型即可)。

与进程类的关系

「进程类」默认用内置匿名管道捕获标准输出。需要自定义时,用 置标准输入 / 置标准输出 / 置标准错误 把本类匿名端交给子进程;未设置的那一路仍走内置重定向。