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.枚举管道())
自由命令:创建管道()(一般不必调,直接声明类型即可)。
与进程类的关系
「进程类」默认用内置匿名管道捕获标准输出。需要自定义时,用 置标准输入 / 置标准输出 / 置标准错误 把本类匿名端交给子进程;未设置的那一路仍走内置重定向。