连接两个TCP套接字而不定义客户端/服务器角色

时间:2012-06-06 13:02:22

标签: python sockets distributed-computing

问题

我想通过TCP连接两个进程,但我不想指定哪个是服务器,哪个是客户端,但是他们知道彼此的IP和主机。他们应该决定自己哪个是服务器,哪个是客户端,然后启动连接。

背景

我正在开发一个双向分布式框架,与RPC相比,没有客户端/服务器模型。相反,分布式组件应该能够通过指定主机和端口来相互通信。

编辑:这个概念超越了套接字连接的实现细节。这应该是一个新概念,用于简化software engineering方面的分布式应用程序设计。这与RPC和SOA(面向服务器/客户端)和面向消息的系统(需要使用IMO非直观模式)形成对比。

解决方案不得

  • 通过UDP定义协议,因为我需要TCP可靠性和SSL使用的可能性
  • 使用像ZeroMQ这样的框架,因为我无法在目标平台上使用二进制包
  • 编辑:全局消息代理/名称服务器,因为它应该是一个没有额外进程的轻量级解决方案。添加这样的节点只会重新引入客户端/服务器概念

更新

讨论之后似乎只有一种有用的方法:每个对等体都需要一个列表套接字(当然,你不能做任何自动发现)。在连接请求中,如果还没有打开的连接,节点将尝试连接到另一个对等端。

如果连接同时进行,这可能会有问题,因此我们最终会在两个对等体之间建立两个连接。现在的问题是如何在异步上下文中处理它。我不认为这在评论中如下所述那么简单,因为我们需要保证只关闭一个连接。我认为这项任务需要像2PC这样的协议。

2 个答案:

答案 0 :(得分:8)

在我看来,你有点困惑。是的,软件工程文献讨论了服务器/客户端模型,并将其与其他模型(如点对点)进行了对比。但是,分布式系统的核心始终是在某处使用服务器/客户端模型,因为实际上没有其他方式可以通过Internet进行通信。

(从技术上讲,你应该能够通过互联网发送任何类型的IP数据报,因此你可以尝试发明一种不是服务器/客户端的不同传输协议,但我假设你没有想要将新的传输层安装到操作系统的网络堆栈中,此外还有其他问题,例如可能阻碍此类通信的中置NAT设备。)

如果你要限制所有类型的通信,两个节点如何“自己决定”谁将要收听?谁将要连接?您只能通过Internet可靠地使用两种协议:UDP和TCP。它们都涉及一个进程设置一个侦听套接字,另一个进程向所述侦听服务器发送消息(UDP)或执行连接尝试(TCP)。

您在建立连接之前执行UDP消息的想法并没有真正改变任何事情。侦听UDP消息的进程仍然是服务器。如果有的话,它只是意味着除了监听或启动TCP连接之外,所有节点也必须是UDP监听服务器。

如果您不想在握手发生之前在同级中拥有任何类型的侦听套接字,则需要拥有某种类型的第三方消息代理。这是显而易见的,因为没有侦听套接字就无法进行通信,因此您无法开始执行所述握手。捉住22。

还有一个明显的解决方案:让每个对等体监听连接,然后当两个对等体想要相互通信时,使两者都试图相互连接:如果两者都不能连接,则报告这两个对等体都不能作为一台服务器。如果可以连接,请照常进行。如果两者都可以连接,则丢弃第二个连接并继续使用第一个连接。

我的建议是让你研究像BitTorrent这样的协议功能(它们的功能与我上面详述的解决方案非常相似)。可选地,在您弄清楚这一点之后,您可能希望查看NAT遍历解决方案,例如STUN,以确保您不会经常遇到“两个对等体都不是服务器”的情况,但这是一个单独的问题。

答案 1 :(得分:2)

如果你想让两个同伴找到对方,你或者要去看看:

  • 广播方案:zeromq可以使用,但如果你不能使用它,你可以尝试使用ip多播
  • 您自己的发现服务

引导点对点应用程序将需要以上之一。大多数人最终使用网络“广播”一个Bittorrent Tracker URL,然后帮助同伴找到彼此。

根据您的要求,我强烈建议您研究IP多播。我使用Twisted(http://twistedmatrix.com/documents/current/core/howto/udp.html)创建一个简单的UDP协议。我用它来启动我桌面计算机上的主进程和一组远程计算机上的多个工作进程,以协调站点的负载测试。我不会说这是微不足道的,但效果很好。

关键是你必须定义自己的简单有线协议,可能是简单的netstring(+)。我会使用像JSON这样的简单结构化消息格式来简化序列化,并允许您轻松编码消息中的元数据。

如果您使用2个UDP多播端口,一个用于发现,另一个用于要在节点之间发送的消息或数据,您将有更简单的时间。

我希望这会有所帮助,但如果没有更多有关您实际想要实现的内容的详细信息,则很难更具体。