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

sch*_*mar 10 python sockets distributed-computing

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

背景

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

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

解决方案一定不能

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

更新

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

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

mpo*_*tes 8

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

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

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

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

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

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

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


std*_*err 2

如果您希望两个同伴找到彼此,您必须查看以下任一内容:

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

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

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

关键是您必须定义自己的简单有线协议,可能是简单的网络字符串 (+)。我将使用简单的结构化消息格式(例如 JSON)来轻松序列化,并允许您轻松地在消息中对元数据进行编码。

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

我希望这会有所帮助,但如果没有更多关于您实际想要完成的事情的详细信息,就很难更具体。