'localhost' 没有防火墙弹出窗口的连接
'localhost' connection without firewall popup
考虑以下 R 脚本:
con <- socketConnection(host = "localhost", port = 8, server = TRUE, blocking = TRUE, open = "a+b")
close(con = con)
将这些行保存为 .R 文件,随后 运行 从命令行生成(在 Windows 上)防火墙警告。至少,如果"Windows Firewall with Advanced Security"下的R没有规则出现在第一次之后。有人告诉我在 Mac 上也会发生同样的情况,但我自己无法验证这一点。如何更改它以允许本地主机环回,但避免弹出窗口?
上下文:我为使用并行处理的人编写了一些代码(在一台本地计算机上)。然而,这个警告突然出现在他们的屏幕上,他们开始怀疑了。愚蠢的是,即使人们点击否或忽略弹出窗口,并行处理似乎仍然有效。我认为这是一个迹象,表明可以修改此代码以不提供此弹出窗口并仍然起作用。
我在其他语言中看到过非常相似的问题 (1, 2, 3),我想知道是否可以用 R 做同样的事情。
Windows 10 防火墙首次提示示例:
我的感觉是,解决此问题的最简单方法是在应用程序安装过程中添加防火墙规则。
- 您可以使用 netsh 添加规则(需要管理员权限)以编程方式启用防火墙访问。
我在下面提供了一个示例脚本,希望这能帮助您指明正确的方向。
示例防火墙配置脚本
netsh advfirewall firewall add rule name="RScript" action=allow program="C:\Program Files\Microsoft\R Client\R_SERVER\bin\x64\Rscript.exe" enable=yes Localip="127.0.0.1" localport="9999" protocol=tcp interfacetype=any profile=private dir=in
命令输出:
PS <hidden>\dev\Whosebug353848> netsh advfirewall firewall add rule name="RScript" action=allow program="C
:\Program Files\Microsoft\R Client\R_SERVER\bin\x64\Rscript.exe" enable=yes Localip="127.0.0.1" localport="9999" protoco
l=tcp interfacetype=any profile=private dir=in
Ok.
已添加防火墙规则
假设您 运行 R 文件使用 RScript,上面的 netsh
脚本将使 RScript 应用程序能够使用私有网络上的 TCP 访问端口 9999 上的环回地址 127.0.0.1网络。 从现在开始,您应该不会收到防火墙提示。
没有防火墙提示的命令行
c:\<hidden>\dev\Whosebug353848> Rscript.exe .\server.R
Listening...
为什么要这样做?好吧,据我所知,即使在使用环回连接器时,也无法在不触发 Windows Defender 防火墙提示的情况下在 Windows 上使用 R 的 base::socketConnection
。 有趣的是,如果您使用 Java,您不会收到提示。我查看了这两种实现,但无法确定为什么不这样做。
测试服务器代码:
server <- function() {
while (TRUE) {
writeLines("Listening...")
con <- socketConnection(host = "loopback",
port = 9999,
server = TRUE,
blocking = TRUE,
timeout = 0,
open = "r+")
data <- readLines(con, 1)
print(data)
response <- toupper(data)
writeLines(response, con)
close(con)
}
}
server()
测试客户端代码
client <- function() {
while (TRUE) {
con <- socketConnection(host = "loopback",
port = 9999,
server = FALSE,
blocking = TRUE,
open = "r+")
f <- file("stdin")
open(f)
print("Enter text to be upper-cased, q to quit")
sendme <- readLines(f, n = 1)
if (tolower(sendme) == "q") {
break
}
write_resp <- writeLines(sendme, con)
server_resp <- readLines(con, 1)
print(paste("Your upper cased text: ", server_resp))
close(con)
}
}
client()
(我对防火墙规则的看法,请看最后)
该功能似乎根本不存在。
在 C 中,您使用 socket
、bind
和 listen
调用创建服务器套接字,并使用 accept
调用获取传入连接。
src\modules\internet\sock.c 是套接字处理程序代码,它有两个打开套接字的函数,Sock_connect
打开并连接一个套接字,所以这是给客户端的,int Sock_open(Sock_port_t port, Sock_error_t perr)
是一个打开服务器套接字(实际的 accept 调用在 Sock_listen
中)。问题是这个 Sock_open
只有一个 port
参数,而 host/interface 是硬编码的:
/* open a socket for listening */
int Sock_open(Sock_port_t port, Sock_error_t perr)
{
int sock;
struct sockaddr_in server;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return Sock_error(perr, errno, 0);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons((short)port);
if ((bind(sock, (struct sockaddr *)&server, sizeof(server)) < 0) ||
(listen(sock, MAXBACKLOG) < 0)) {
close(sock);
return Sock_error(perr, errno, 0);
}
return sock;
}
它绑定并监听 INADDR_ANY,这意味着您 PC 的所有接口(不仅仅是环回),并且它肯定会触发防火墙。
该函数是从相邻的 Rsock.c 调用的,仍然只有一个端口参数,其他所有内容似乎都早了一步,在 sockconn.c:
中
static Rboolean sock_open(Rconnection con)
{
Rsockconn this = (Rsockconn)con->private;
int sock, sock1, mlen;
int timeout = this->timeout;
char buf[256];
if(timeout == NA_INTEGER || timeout <= 0) timeout = 60;
this->pend = this->pstart = this->inbuf;
if(this->server) {
sock1 = R_SockOpen(this->port);
最后一行忽略了 RSockconn 的主机部分,尽管它包含这样的字段:
/* used in internet module */
typedef struct sockconn {
int port;
int server;
int fd;
int timeout;
char *host;
char inbuf[4096], *pstart, *pend;
} *Rsockconn;
(这个是在外面定义的,在src\include\Rconnections.h)
不幸的是,这不能解决您的问题,这就是您拥有它的原因。您可以考虑为 R 的开发人员提交错误报告。评论表明他们从古代就获得了网络代码,那时防火墙和互联网安全不像现在这样令人担忧:
/* Simple sockets interface derived from the sockets UICI
implementation in Appendix B of Practical UNIX Programming,
K. A. Robbins and S. Robbins, Prentice Hall, 1996. */
真好,21 年前的事了。
本来我不想偷别人的netsh东西,但我想你可能会得到错误的建议。实际上你不应该允许任何东西,而是阻止一切:
netsh advfirewall firewall add rule name="Rtest" dir=in action=block program="<location and name of your executable>"
就是这样。问题是环回接口根本没有防火墙(所以到 127.0.0.1 的连接总是有效 - 我也测试过它,只是为了安全起见),你不希望任何其他人访问你的程序。我在其他答案中看到 'allow'-s ,而您不希望那样。根据其他用途,你可能要用'localport=8'and/or'protocol=tcp'来限制规则,但是block部分是肯定的。
您基本上被迫使用 Windows 防火墙,因为它带有 Windows。因此,也许在您的 .R 文件中包含一个 .bat 文件,它会创建一个异常并告诉用户 运行 它?或者用 IExpress 制作一个 .exe 安装程序?这可能会成功。
不过,我会推荐 .exe 安装程序路径,因为 .bat 文件似乎也有点可疑,因为不懂技术的用户在请求管理员权限时会大叫狼来了。如果您更喜欢 .bat 文件路由,netsh 命令可以为任何程序创建防火墙例外。
这个通过使用 dir=out 开关接受传出连接,并通过 action=allow 开关启用例外
netsh advfirewall firewall add rule name="PROGRAM_NAME" dir=out action=allow program="C:\PROGRAMPATH" enable=yes
这个通过使用 dir=in 开关接受传入连接,并通过 action=allow 开关启用例外
netsh advfirewall firewall add rule name="PROGRAM_NAME" dir=out action=allow program="C:\PROGRAMPATH" enable=yes
How to add a rule to Windows Firewall - DigitalCitizen
Online Tech Tips - Adjust Windows 10 Firewall Rules & Settings
使用 PSOCK 集群的另一种方法是使用 callr for running multiple R sessions in the background. The future.callr package (*) provides parallel backend for the future 框架(免责声明:我是作者)。它允许您在不通过套接字(因此没有防火墙)的情况下并行化所有操作系统,包括 Windows。示例:
library("future")
plan(future.callr::callr)
y <- future_lapply(x, FUN = my_fcn_in_parallel)
它也适用于 doFuture for the foreach 框架。示例:
library("doFuture")
plan(future.callr::callr)
registerDoFuture()
y <- foreach(i in seq_along(x)) %dopar% my_fcn_in_parallel(x[[i]])
仅供参考,对于 PSOCK 集群,使用 plan(multisession)
。
(*) future.callr 自 2018-02-13 起在 CRAN 上 将在其依赖的开发人员版本提交给 CRAN 后立即提交给 CRAN。
考虑以下 R 脚本:
con <- socketConnection(host = "localhost", port = 8, server = TRUE, blocking = TRUE, open = "a+b")
close(con = con)
将这些行保存为 .R 文件,随后 运行 从命令行生成(在 Windows 上)防火墙警告。至少,如果"Windows Firewall with Advanced Security"下的R没有规则出现在第一次之后。有人告诉我在 Mac 上也会发生同样的情况,但我自己无法验证这一点。如何更改它以允许本地主机环回,但避免弹出窗口?
上下文:我为使用并行处理的人编写了一些代码(在一台本地计算机上)。然而,这个警告突然出现在他们的屏幕上,他们开始怀疑了。愚蠢的是,即使人们点击否或忽略弹出窗口,并行处理似乎仍然有效。我认为这是一个迹象,表明可以修改此代码以不提供此弹出窗口并仍然起作用。
我在其他语言中看到过非常相似的问题 (1, 2, 3),我想知道是否可以用 R 做同样的事情。
Windows 10 防火墙首次提示示例:
我的感觉是,解决此问题的最简单方法是在应用程序安装过程中添加防火墙规则。
- 您可以使用 netsh 添加规则(需要管理员权限)以编程方式启用防火墙访问。
我在下面提供了一个示例脚本,希望这能帮助您指明正确的方向。
示例防火墙配置脚本
netsh advfirewall firewall add rule name="RScript" action=allow program="C:\Program Files\Microsoft\R Client\R_SERVER\bin\x64\Rscript.exe" enable=yes Localip="127.0.0.1" localport="9999" protocol=tcp interfacetype=any profile=private dir=in
命令输出:
PS <hidden>\dev\Whosebug353848> netsh advfirewall firewall add rule name="RScript" action=allow program="C
:\Program Files\Microsoft\R Client\R_SERVER\bin\x64\Rscript.exe" enable=yes Localip="127.0.0.1" localport="9999" protoco
l=tcp interfacetype=any profile=private dir=in
Ok.
已添加防火墙规则
假设您 运行 R 文件使用 RScript,上面的 netsh
脚本将使 RScript 应用程序能够使用私有网络上的 TCP 访问端口 9999 上的环回地址 127.0.0.1网络。 从现在开始,您应该不会收到防火墙提示。
没有防火墙提示的命令行
c:\<hidden>\dev\Whosebug353848> Rscript.exe .\server.R
Listening...
为什么要这样做?好吧,据我所知,即使在使用环回连接器时,也无法在不触发 Windows Defender 防火墙提示的情况下在 Windows 上使用 R 的 base::socketConnection
。 有趣的是,如果您使用 Java,您不会收到提示。我查看了这两种实现,但无法确定为什么不这样做。
测试服务器代码:
server <- function() {
while (TRUE) {
writeLines("Listening...")
con <- socketConnection(host = "loopback",
port = 9999,
server = TRUE,
blocking = TRUE,
timeout = 0,
open = "r+")
data <- readLines(con, 1)
print(data)
response <- toupper(data)
writeLines(response, con)
close(con)
}
}
server()
测试客户端代码
client <- function() {
while (TRUE) {
con <- socketConnection(host = "loopback",
port = 9999,
server = FALSE,
blocking = TRUE,
open = "r+")
f <- file("stdin")
open(f)
print("Enter text to be upper-cased, q to quit")
sendme <- readLines(f, n = 1)
if (tolower(sendme) == "q") {
break
}
write_resp <- writeLines(sendme, con)
server_resp <- readLines(con, 1)
print(paste("Your upper cased text: ", server_resp))
close(con)
}
}
client()
(我对防火墙规则的看法,请看最后)
该功能似乎根本不存在。
在 C 中,您使用 socket
、bind
和 listen
调用创建服务器套接字,并使用 accept
调用获取传入连接。
src\modules\internet\sock.c 是套接字处理程序代码,它有两个打开套接字的函数,Sock_connect
打开并连接一个套接字,所以这是给客户端的,int Sock_open(Sock_port_t port, Sock_error_t perr)
是一个打开服务器套接字(实际的 accept 调用在 Sock_listen
中)。问题是这个 Sock_open
只有一个 port
参数,而 host/interface 是硬编码的:
/* open a socket for listening */
int Sock_open(Sock_port_t port, Sock_error_t perr)
{
int sock;
struct sockaddr_in server;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return Sock_error(perr, errno, 0);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons((short)port);
if ((bind(sock, (struct sockaddr *)&server, sizeof(server)) < 0) ||
(listen(sock, MAXBACKLOG) < 0)) {
close(sock);
return Sock_error(perr, errno, 0);
}
return sock;
}
它绑定并监听 INADDR_ANY,这意味着您 PC 的所有接口(不仅仅是环回),并且它肯定会触发防火墙。
该函数是从相邻的 Rsock.c 调用的,仍然只有一个端口参数,其他所有内容似乎都早了一步,在 sockconn.c:
中static Rboolean sock_open(Rconnection con)
{
Rsockconn this = (Rsockconn)con->private;
int sock, sock1, mlen;
int timeout = this->timeout;
char buf[256];
if(timeout == NA_INTEGER || timeout <= 0) timeout = 60;
this->pend = this->pstart = this->inbuf;
if(this->server) {
sock1 = R_SockOpen(this->port);
最后一行忽略了 RSockconn 的主机部分,尽管它包含这样的字段:
/* used in internet module */
typedef struct sockconn {
int port;
int server;
int fd;
int timeout;
char *host;
char inbuf[4096], *pstart, *pend;
} *Rsockconn;
(这个是在外面定义的,在src\include\Rconnections.h)
不幸的是,这不能解决您的问题,这就是您拥有它的原因。您可以考虑为 R 的开发人员提交错误报告。评论表明他们从古代就获得了网络代码,那时防火墙和互联网安全不像现在这样令人担忧:
/* Simple sockets interface derived from the sockets UICI
implementation in Appendix B of Practical UNIX Programming,
K. A. Robbins and S. Robbins, Prentice Hall, 1996. */
真好,21 年前的事了。
本来我不想偷别人的netsh东西,但我想你可能会得到错误的建议。实际上你不应该允许任何东西,而是阻止一切:
netsh advfirewall firewall add rule name="Rtest" dir=in action=block program="<location and name of your executable>"
就是这样。问题是环回接口根本没有防火墙(所以到 127.0.0.1 的连接总是有效 - 我也测试过它,只是为了安全起见),你不希望任何其他人访问你的程序。我在其他答案中看到 'allow'-s ,而您不希望那样。根据其他用途,你可能要用'localport=8'and/or'protocol=tcp'来限制规则,但是block部分是肯定的。
您基本上被迫使用 Windows 防火墙,因为它带有 Windows。因此,也许在您的 .R 文件中包含一个 .bat 文件,它会创建一个异常并告诉用户 运行 它?或者用 IExpress 制作一个 .exe 安装程序?这可能会成功。
不过,我会推荐 .exe 安装程序路径,因为 .bat 文件似乎也有点可疑,因为不懂技术的用户在请求管理员权限时会大叫狼来了。如果您更喜欢 .bat 文件路由,netsh 命令可以为任何程序创建防火墙例外。
这个通过使用 dir=out 开关接受传出连接,并通过 action=allow 开关启用例外
netsh advfirewall firewall add rule name="PROGRAM_NAME" dir=out action=allow program="C:\PROGRAMPATH" enable=yes
这个通过使用 dir=in 开关接受传入连接,并通过 action=allow 开关启用例外
netsh advfirewall firewall add rule name="PROGRAM_NAME" dir=out action=allow program="C:\PROGRAMPATH" enable=yes
How to add a rule to Windows Firewall - DigitalCitizen
Online Tech Tips - Adjust Windows 10 Firewall Rules & Settings
使用 PSOCK 集群的另一种方法是使用 callr for running multiple R sessions in the background. The future.callr package (*) provides parallel backend for the future 框架(免责声明:我是作者)。它允许您在不通过套接字(因此没有防火墙)的情况下并行化所有操作系统,包括 Windows。示例:
library("future")
plan(future.callr::callr)
y <- future_lapply(x, FUN = my_fcn_in_parallel)
它也适用于 doFuture for the foreach 框架。示例:
library("doFuture")
plan(future.callr::callr)
registerDoFuture()
y <- foreach(i in seq_along(x)) %dopar% my_fcn_in_parallel(x[[i]])
仅供参考,对于 PSOCK 集群,使用 plan(multisession)
。
(*) future.callr 自 2018-02-13 起在 CRAN 上 将在其依赖的开发人员版本提交给 CRAN 后立即提交给 CRAN。