【问题标题】:Non blocking sockets in R?R中的非阻塞套接字?
【发布时间】:2020-09-03 13:47:20
【问题描述】:

我正在尝试使用套接字在 R 会话之间进行通信,但无法让它们按照帮助文件的建议行事 (?read.socket)。

在一个 Rstudio 会话中,我运行以下命令

sock_server <- make.socket(port = 22222, server = TRUE)
write.socket(sock_server, "Ahoy-hoy")

然后在另一个我运行

sock <- make.socket(port = 22222, server = FALSE)
read.socket(sock, loop = FALSE)

我确实看到了友好的问候。

但是,如果我重新运行 read.socket 行而不发送任何其他内容,它就会挂起,只有在发送更多信息时才会返回。选项loop = FALSE 应该控制这种行为,如果没有任何内容等待读取,可能会返回一个空字符串,但它不会改变任何东西。

我在 MacOS 和 Windows 上都试过了,两种情况都一样。

知道如何让套接字正常运行吗?


我现在已经在命令行中尝试了 RStudio、RGui 和 R 的各种组合,就我所见,它在所有这些组合中的行为都是相同的。

我的最终目标是在 R 中拥有可以处理来自外部主机的 FIX 连接的东西。除了上述很难解决的问题外,它基本上可以使用这些套接字功能。

我愿意使用人们在这些事情上使用的任何其他东西。


这是第二次成功的尝试!但不幸的是,只有在 Mac 上,Windows 才会做一些奇怪的事情。

在基础 R 中使用二进制连接和一组不同的套接字函数,在服务器端你这样做

sock_server <- socketConnection(port = 22222, server = TRUE, open = 'a+b')
fix_message <- gsub("\\|","\001","8=FIX.4.4|9=106|35=0|34=1234|49=abc|56=def|10=999|")
writeBin(charToRaw(fix_message), sock_server)

在客户端

sock <- socketConnection(port = 22222, server = FALSE, open = 'a+b')
rawToChar(readBin(sock, raw(), n = 32))

请注意,我发送的消息中没有换行符(这是 FIX 消息的一个功能)。

在 Mac 上,这可以按预期工作 - 运行两次 readBin 行会为您提供整个消息,您可以将其粘贴回去,但在 Windows 上,消息的第二部分会消失!

# Mac
> rawToChar(readBin(sock, raw(), n = 32))
[1] "8=FIX.4.4\0019=106\00135=0\00134=1234\00149="
> rawToChar(readBin(sock, raw(), n = 32))
[1] "abc\00156=def\00110=999\001"

# Windows
> rawToChar(readBin(sock, raw(), n = 32))
[1] "8=FIX.4.4\0019=106\00135=0\00134=1234\00149="
> rawToChar(readBin(sock, raw(), n = 32))
[1] ""

我在两个平台上都使用 R 4.0.2。有人知道如何在 Windows 上执行此操作吗?

【问题讨论】:

  • 只是猜测:这些套接字函数是否与 Rstudio 兼容?您是否尝试过运行两个 Rgui.exe 或两个终端会话来查看会发生什么?

标签: r sockets


【解决方案1】:

我也尝试过未来的包:

library("future")
plan(multiprocess)


mySocketRead<- function()
{
  sock <- make.socket(port = 22222, server = FALSE)
  msg <-read.socket(sock, loop = FALSE)
  #print(msg)
  print("read done ")
}


# normal non-blocking
res %<-% mySocketRead()

print("here we go")

但是这个例子在读时也是阻塞的,所以看来是read.socket函数的普遍问题。

我还有 2 个想法:

想法 A:也许您可以相互交换您的服务器和客户端,因为如果服务器总是阻塞在一个永久读取循环中,它可能更容易接受,但这取决于您的用例。

想法 B: 使用 socketConnection 实现并转换你的字符串 想要发送到问题较少的字符串。 我确实认为,您从 mac 到 windows 的“丢失的字符串”出现了,因为您确实使用了“4\0019”字符串文字,这可能会被不同的套接字实现“解释”错误。 一般来说,使用 base64encode 和 base64decode 函数很有用 也许您还应该添加一个校验和以确保您的传输成功。

require(base64enc)

#send
fix_message <- gsub("\\|","001","8=FIX.4.4|9=106|35=0|34=1234|49=abc|56=def|10=999|")
fix_message_base64 <- base64encode(charToRaw(fix_message))
writeBin(charToRaw(fix_message_base64), sock_server)

#receive
fix_message_input_base64_raw <-readBin(sock, raw(), n = 32)
fix_message_input_raw <-base64decode(fix_message_base64)
fix_message_input <-rawToChar(fix_message_input_raw)

如果这没有帮助,您可以使用wireshark 调试您的网络流量。

旧的不起作用,但是是一个示例,如何等待 X 秒以使函数 Y 完成:

我认为在函数中使用套接字并等到该函数超时。这也会阻塞,但不会永远阻塞。


require(R.utils)

## function that can take a long time
socketRead<- function()
{
    sock <- make.socket(port = 22222, server = FALSE)
    read.socket(sock, loop = FALSE)
    return("read")
}

# call read function
waitingTimeInSeconds=10
withTimeout(socketRead(), timeout = waitingTimeInSeconds, onTimeout = "error")

找到函数withTimout here的文档

【讨论】:

  • 好主意,但这对我不起作用 - 它仍然挂起。我在withTimeout() 调用之外尝试了make.socket()。我还用Sys.sleep(100) 尝试过,它会在 10 秒后中断。
  • 我认为空字符 (\001) 不是问题所在。我尝试使用 base64 结束编码/解码,它有同样的问题 - 在 mac 上很好,但在 Windows 机器上,如果要读取的剩余消息短于n=32,那么它就会丢失。我想我可以设置n=1,但这感觉像是一个愚蠢的解决方案,我希望有一个更好的解决方案。
  • 它需要固定长度还是只使用socketConnectionreadLines,类似于此处找到的解决方案:r.789695.n4.nabble.com/…
  • 也许你填写找到你的答案,当你弄清楚,在什么时候(传输,转换,..)你的字符串被修剪,你可以使用wireshark观察通过套接字传输的信息
  • @Roger-123 这是同样的问题,但看起来他发送的消息中有换行符。我必须使用二进制连接open = 'a+b' 才能使用 writeBin 发送没有换行符的消息。哦。看来readLines 仍然适用于二进制连接!它既不会阻止也不会修剪消息,您可以关闭警告。如果有人想写下来,这里很容易赏金......
【解决方案2】:

我最终得到的解决方案几乎是上述两种方法的组合。

服务器端做

sock_server <- socketConnection(port = 22222, server = TRUE, open = 'a+b')
fix_message <- gsub("\\|","\001","8=FIX.4.4|9=106|35=0|34=1234|49=abc|56=def|10=999|")
writeBin(charToRaw(fix_message), sock_server)

客户端会这样做

sock <- socketConnection(port = 22222, server = FALSE, blocking = FALSE, open = 'a+b')
readLines(sock, warn = FALSE)
#> [1] "8=FIX.4.4\0019=106\00135=0\00134=1234\00149=abc\00156=def\00110=999\001"
readLines(sock, warn = FALSE)
#> character(0)

没有丢失消息,没有阻塞,并且在我一直使用的 Mac 和 Windows 机器上都可以使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-31
    • 2013-10-15
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多