Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Connect two TCP sockets without defining client/server role [closed]

Question

I want to connect two processes via TCP but I don't want have to specify which of them is the server and which is the client but they know the IP and host of each other. They should decide on their own which is the server and which is the client and then initiating the connection.

Background

I am working on a bidirectional distributed framework where - in contrast to RPC - there is no client/server model. Instead the distributed components should just be able to talk to each other by specifying a host and port.

Edit: The concept goes beyond the implementation details of a socket connection. This should be a new concept to simplify designing a distributed application in terms of software engineering. This is in contrast to RPC and SOA (which are Server/Client oriented) and message oriented systems (which demand the usage of IMO un-intuitive patterns).

The solution must not

  • defining a protocol via UDP, because I need the TCP reliability and the possibility of SSL usage
  • using a framework like ZeroMQ, because I cannot use binary packages on my target platform
  • edit: a global message broker / name server because it should be a lightweight solution without an additional process. And adding such a node will just reintroduce the client/server concept

Update

After the discussion there seems only one useful approach: Every peer need to have a listing socket (or you cannot do any auto-discovery of course). On a connection request the node will try to connect to the other peer if there isn't already an open connection.

This could be problematic if the connection is done simultaneous, so we will end up with two connections between two peers. The question is now how to deal with that in an async context. I don't think this is as easy as said below in comments because we need to guarantee that only one connection is closed. I think a protocol like 2PC is needed for this task.

like image 262
schlamar Avatar asked Jun 06 '12 13:06

schlamar


2 Answers

It appears to me you are slightly confused. Yes, software engineering literature talks about the server/client model and contrasts it with other models, such as peer-to-peer. However, at their core, distributed systems always end up using a server/client model somewhere, because there really is no other way to communicate through the Internet.

(Technically, you should be able to send any kind of IP datagrams through the Internet, so you could attempt to invent a different transport protocol that isn't server/client at its core, but I'm assuming you do not want to install new transport layers into the networking stacks of the OSes, plus, there's other gotchas such as home NAT appliances that might be in the middle that would thwart such communication.)

How can the two nodes "decide between themselves" who is going to listen and who is going to connect if you're restricting all kind of communication from the get go? You can only reliably use two protocols through the Internet: UDP and TCP. Both of them involve a process setting up a listening socket and the other sending a message (UDP) or performing a connection attempt (TCP) to said listening server.

Your idea of doing UDP messages before establishing the connection doesn't really change anything. A process listening to UDP messages is still a server. If anything, it just means that additionally to either listening to or initiating a TCP connection, all the nodes will have to be UDP listening servers as well.

You will need to have a third-party message broker of some kind if you do not want to have any kind of listening sockets in the peers before the handshaking happens. This is obvious, because you can't communicate without listening sockets, so you can't perform said handshake to begin with. Catch-22.

There's also the obvious solution: make each peer listen to connections, then when two peers want to talk to each other, make both attempt to connect to each other: if neither can connect, report that neither peer is able to function as a server. If one can connect, proceed as normal. If both can connect, discard the second connection and continue using the first connection.

My suggestion would be for you to look into how protocols like BitTorrent function (they function quite similarly to the solution I detailed above). Optionally, after you've figured this out, you might want to look into NAT traversal solutions such as STUN to ensure you don't run into the "neither peer can be a server" situation as often, but that's a separate issue.

like image 126
mpontes Avatar answered Nov 28 '22 09:11

mpontes


If you want two peers to find each other you're going to either have to look into either:

  • a broadcast scheme: zeromq would work but if you can't use that you can try to use ip multicasting
  • your own discovery service

Bootstrapping peer-to-peer applications is going to require one of the above. Most end up using the web to "broadcast" a Bittorrent Tracker URL and that then helps peers find one another.

Given your requirements I'd strongly encourage you to look into IP Multicast. I used Twisted (http://twistedmatrix.com/documents/current/core/howto/udp.html) to create a simple UDP protocol. I used this to start up a master process on my desktop machine and multiple worker processes on a set of remote machines to coordinate a load test of a site. I won't say it's trivial but it works quite well.

The key is that you must define your own simple wire protocol, possible something as simple netstring ( + ). I would use a simple structured message format like JSON for easy serialization and to allow you to easily encode metadata in your messages.

You will have a simpler time if you use 2 UDP Multicast Ports, one for discovery and the other for messages or data that you want to send between nodes.

I hope that helps but without more details about what you actually want to accomplish it's difficult to be much more specific.

like image 22
stderr Avatar answered Nov 28 '22 08:11

stderr