(可能只是知道Unix库就足以回答这个问题了,所以如果你不认识JoCaml,请继续阅读。)
我在JoCaml有两个程序。服务器,准备返回端口12345上的数字的平方
(* p.ml *)
def f (x) =
print_string ("["^string_of_int(x)^"] "); flush stdout;
reply x*x to f
in Join.Ns.register Join.Ns.here "square" f
;;
let wait =
def x () & y () = reply to x
in x
let main =
Join.Site.listen (Unix.ADDR_INET (Join.Site.get_local_addr(), 12345));
wait()
和客户端,准备使用服务器的square函数
(* q.ml *)
let server =
let server_addr = Unix.gethostbyname "192.168.0.10" in
Join.Site.there (Unix.ADDR_INET(server_addr.Unix.h_addr_list.(0),12345))
let ns = Join.Ns.of_site server
let sqr = (Join.Ns.lookup ns "square": int -> int)
let _ = Printf.printf "%d\n" (sqr 3)
如果两个程序在同一台机器上运行,这一切都正常。但我的目标是将它们放在两台不同的机器上。所以上面的IP应该成为其他一些公共IP。由于我只有一台机器来测试这个,我决定在那台机器上运行这两个程序,而不是上面的192.168.0.10,我的机器的公共IP。不幸的是,它不起作用,连接超时。
有什么想法吗?
[EDITED]
我上面写的代码是我从JoCaml手册中得到的一个例子,因为它是我自己的代码片段的类似和简化版本,问题出现了。我正在编写的程序旨在创建一个JoCaml运行时的P2P网络,它们都进行私有计算,并在本地存储结果,依赖于存储在网络其他对等方的数据。所以,我希望有一组对等体都运行与q.ml“相似”的东西,因为它们需要连接到其他机器并从中获取所需的信息。
每个对等体都需要保留其对等体的列表。然后,您可以以简单的方式查询网络中的某些值。每个对等体将检查它是否知道该值:如果是,则返回它,如果不是,则询问其对等体(等等,递归地)。 P2P架构非常适合我的目的。 (由于他的答案中提到的性能和可靠性问题,Gilles建议的集中式拓扑不适用于我的特定问题。)我引入了一个特殊的引导对等体,所有代码都知道并且任何新对等体将首先连接到该对等体访问网络。一旦新对等体被引导对等体认证,它应该加入网络并且自己成为一流的对等体(并且可以从那时起忽略引导对等体)。这些对等体将直接在它们之间进行通信(1-1),因此需要为每对任意对等体建立一种在它们之间建立连接的方法。此外,由于我希望拥有适当凭据的任何人能够加入此网络,无论他们的网络技能如何,我都无法找到人们需要配置其路由器加入P2P网络的解决方案。他们应该只是运行软件。
我的要求是:
如果我们不需要,我目前的工作情况很好2.有什么建议可以解决最初的问题但是在这个P2P环境中?
(请注意,P2P框架只是达到目的的一种手段。是的,我希望有一些效果很好的东西,但我不打算为JoCaml开发最终的超级通用P2P框架。我我希望写一个简单的事情来完成这项工作。)
答案 0 :(得分:2)
(我认为您的问题在于IP网络拓扑,而不是编程本身,但您需要了解此背景以在JoCaml中进行编程。)
很久以前,互联网上的每台计算机都有一个IP地址,如果您知道其IP地址,就可以与该计算机通信。 (路由器每个接口有一个IP地址,但这只是网络管理员关心的问题。)啊,为了过去的美好时光。
现在事情变得更加复杂了。内联网上的计算机通常只有一个在该Intranet上有效的地址,即所谓的private address。 192.168.0.10就是这样一个私人地址。您只能在该Intranet内与具有私人地址的计算机通信。当计算机需要与外部建立连接时,network address translation (NAT)用于使特定连接起作用。 NAT为内联网计算机提供公共地址,但仅对特定连接有效。
我怀疑您遇到的网络拓扑看起来像这样,A
是您的计算机,C
是您最终使用的另一台计算机,R
是您的家或办公室路由器,1.2.3.4是你所谓的机器的公共IP(实际上,你的网络):
C [5.6.7.8] ←———→ [1.2.3.4] R [192.168.0.1] ←———→ [192.168.0.10] A
在这种情况下,C
无法使用192.168.0.10地址与A
通信,因为该地址仅在Intranet上有意义。如果C
可以与A
进行通信,则必须使用1.2.3.4,并且R
必须配置为将发往1.2.3.4的数据包中继到A
(在典型情况下)配置,R
只会在某些TCP或UDP端口上执行此操作(如果有的话)。但A
使用1.2.3.4作为地址无法与自己对话:来自内部,如果有的话,这可能只会到达R。
这个问题 - 网络中的参与者没有全局可见且唯一的地址 - 是可能的,但理论上很难解决,并且可能但在实践中很难解决。据我所知,Jocaml的库使用IP地址和端口号来唯一地和全局地识别分布式程序中的节点。
鉴于现代网络拓扑结构的复杂性,通常有助于将问题分为两部分:让机器相互通信,实际运行分布式程序。第二部分是你在JoCaml中编程时所做的事情。对于第一部分,ssh是首选工具。将一台计算机或一个网络区域(Internet或Intranet)确定为运行程序的域,并使用SSH隧道将该域外的每台计算机连接到域中的计算机。此方法不适用于所有用例:域外的两台计算机之间的通信将通过域,这可能是性能和可靠性问题。要超越这个范围,您需要配置您的网络,以便每个参与者都有一个每个其他参与者都可以看到的地址(您可能会或可能不会这样做,具体取决于您可以在路由器参与);或者为JoCaml实现一个非全局地址模型(这将是有趣且有用的,但需要付出很多努力)。
答案 1 :(得分:0)
使用
Unix.ADDR_INET(server_addr.Unix.h_addr_list.(0), 12345)
您告诉系统您希望端口仅绑定到本地环回接口。这是一种特殊的虚拟网络设备,可用于快速本地通信。
而是使用
Unix.ADDR_INET (Unix.inet_addr_of_string "0.0.0.0", 12345)
收听您机器的任何网络接口。这样,您的服务器也将接受来自真实网络接口的连接。