Difference between multiplex and multistream - libp2p

What is the difference between multistream (yamux, multistream-select, ..) and multiplex (mplex)?
I'd like to utilize one TCP connection for RPC, HTTP, etc (one client is behind firewall) like this:
conn = tcp.connect("server.com:1111")
conn1, conn2 = conn.split()
stream1 = RPC(conn1)
stream2 = WebSocket(conn2)
..
// received packets tagged for conn1 is forwarded to stream1
// received packets tagged for conn2 is forwarded to stream2
// writing to stream1 tags the packets for conn1
// writing to stream2 tags the packets for conn2
Which one suits this case?

The short answer: mplex and yamux are both Stream Multiplexers (aka stream muxers), and they're responsible for interleaving mulitiple "logical streams" over a single "raw" connection (e.g. TCP). Multistream is used to identify what kind of protocol should be used when sending / receiving data over the stream, and multistream-select lets peers negotiate which protocols are supported by each end and hopefully agree on one to use.
Long answer:
Stream muxing is an interface with several implementations. The "baseline" stream muxer is called mplex - a libp2p-specific protocol with implementations in javascript, go and rust.
Stream multiplexers are "pluggable", meaning that you add support for them by pulling in a module and configuring your libp2p app to use them. A given libp2p application can support several multiplexers at the same time, so for example, you might use yamux as the default but also support mplex to communicate with peers that don't support yamux.
While having this kind of flexibility is great, it also means that we need a way to figure out what stream muxer to use for any specific connection. This is where multistream and multistream-select come in.
Multistream (despite the name) is not directly related to stream multiplexing. Instead, it acts as a "header" for a stream of binary data that contextualizes the stream with a protocol id. The closely-related multistream-select protocol uses mutlistream protocol ids to negotiate what protocols to use for the "next phase" of communication.
So, to agree upon what stream muxer to use, we use multistream-select.
Here's an example the multistream-select back-and-forth:
/multistream/1.0.0 <- dialer says they'd like to use multistream 1.0.0
/multistream/1.0.0 -> listener echoes back to indicate agreement
/secio/1.0.0 <- dialer wants to use secio 1.0.0 for encryption
/secio/1.0.0 -> listener agrees
* secio handshake omitted. what follows is encrypted via secio: *
/mplex/6.7.0 <- dialer would like to use mplex 6.7.0 for stream multiplexing
/mplex/6.7.0 -> listener agrees
This is the simple case where both sides agree upon everything - if e.g. the listener didn't support /mplex/6.7.0, they could respond with na (not available), and the dialer could either try another protocol, ask for a list of supported protocols by sending ls, or give up.
In the example above, both sides agreed on mplex, so future communication over the open connection will be subject the semantics of mplex.
It's important to note that most of the details above will be mostly "invisible" to you when opening individual connections in libp2p, since it's rare to use the multistream and stream muxing libraries directly.
Instead, a libp2p component called the "switch" (also called the "swarm" by some implementations) manages the dialing / listening state for the application. The switch handles the multistream negotiation process and "hides" the details of which specific stream muxer is in use from the rest of the libp2p stack.
As a libp2p developer, you generally dial other peers using the switch interface, which will give you a stream to read from and write to. Under the hood, the switch will find the appropriate transport (e.g. TCP / websockets) and use multistream-select to negotiate encryption & stream multiplexing. If you already have an open connection to the remote peer, the switch will just use the existing connection and open another muxed stream over it, instead of starting from scratch.
The same goes for listening for connections - you give the switch a protocol id and a stream handler function, and it will handle the muxing & negotiation process for you.
Our documentation is a work-in-progress, but there is some information at https://docs.libp2p.io that might help clarify, especially the concept doc on Transports and the glossary. You can also find links to example code.
Improving the docs for libp2p is my main quest at the moment, so please feel free to file issues at https://github.com/libp2p/docs to let me know what your most important missing pieces are.

Related

x/net/http2: ConnState Unable to track

net/http package Server struct in the SDK have ConnState func(net.Conn, ConnState), But not exists in the 'Server' struct of 'x/net/http2'
With the h2c feature, when the state variable is converted to http.StateHijacked , I will no longer know the subsequent state of the connection.
I expect to be able to follow the status of this TCP connection until it is closed.
Is there such a function or a flexible solution? Thank you
You should not use this code in your production.
From x/net/http2:
This is a work-in-progress HTTP/2 implementation for Go.
For your h2c support there is information:
ServeConn serves HTTP/2 requests on the provided connection and blocks until the connection is no longer readable.
ServeConn starts speaking HTTP/2 assuming that c has not had any reads or writes. It writes its initial settings frame and expects to be able to read the preface and settings frame from the client. If c has a ConnectionState method like a *tls.Conn, the ConnectionState is used to verify the TLS ciphersuite and to set the Request.TLS field in Handlers.
ServeConn does not support h2c by itself. Any h2c support must be implemented in terms of providing a suitably-behaving net.Conn.
H2C is not supported with HTTP/2, there are few technical reason why they cut that support. More information you can find in the following Stack thread: Why do web browsers not support h2c (HTTP/2 without TLS)?
You should not know state of connection, you should rely on the language library. If you need to check if connection can accept new connection, you have function here: https://pkg.go.dev/golang.org/x/net/http2#ClientConn.CanTakeNewRequest
Just to take more context, I have one question: Why do you need to know connection state in your application? It is a logic that should be hidden from your app.

What is the difference between DEALER and ROUTER socket archetype in ZeroMQ?

What is the difference between the ROUTER and the DEALER socket archetypes in zmq?
And which should I use, if I have a server, which is receiving messages and a client, which is sending messages? The server will never send a message to a client.
EDIT: I forgot to say that there can be several instances of the client.
For details on ROUTER/DEALER Formal Communication Pattern, do not hesitate to consult the API documentation. There are many features important for ROUTER/DEALER ( XREQ/XREP ) that have nothing beneficial for your indicated use-case.
Many just send, just one just listens?
Given N-clients purely .send() messages to 1-server, which exclusively .recv() messages, but never sends any message back,
the design may benefit from a PUB/SUB Formal Communication Pattern.
In case some other preferences outweight the trivial approach, one may setup a more complex "wireing", using another one-way type of infrastructure, based on PUSH/PULL, and use a reverse setup PUB/SUB, where each new client, the PUB side, .connect()-s to the SUB-side, given a server-side .bind() access-point is on a known, static IP address and the client self-advertises on this signalling channel, that it is alive ( keep-alive with IP-address:port#, where the server-side ought initiate a new PUSHtoPULL.connect() setup onto the client-advertised, .bind()-ready PULL-side access point.
Complex? Rather a limitless tool, only our imagination is our limit.
After some time, one realises all the powers of multi-functional SIG/MSG-infrastructure, so do not hesitate to experiment and re-use the elementary archetypes in more complex, mutually-cooperating distributed systems computing.

How can i force tcp to discard the oldest data segment in the buffer and accept the new data written by the application in NS2

I'm trying to adjust TCP to work well over real-time communication. To do this one of the specification is to force TCP to accept new data written by the application even when the buffer is full which makes TCP sometimes 'unreliable'. This way the applications write calls are never blocked and the timing of the sender application is not broken.
I think there must be an option in NS2 to make it possible.
So, How can I force TCP to discard the oldest data segment in the buffer and accept the new data written by the application in NS2?
You cannot. TCP is a "reliable stream". Any functionality that allowed data to be dropped would be counter to that goal and so there is no such support.
If you want to be able to drop data, you're going to have to switch to something like UDP and implement your own windowing/retry if you want "mostly reliable delivery" instead of "best effort".
If you are going to be dropping data anyway, just drop it before you send it to the socket. You can use select to see if the socket is available for writing, and if not drop the data at the application layer. If it is of the utmost importance that you have the latest freshest data, then see Brian's answer.
Edit
On a side note you may want to google for real time network protocols, and see what already exists.

When to use TCP and HTTP in node.js?

Stupid question, but just making sure here:
When should I use TCP over HTTP? Are there any examples where one is better than the other?
TCP is full-duplex 2-way communication. HTTP uses request/response model. Let's see if you are writing a chat or messaging application. TCP will work much better because you can notify the client immediately. While with HTTP, you have to do some tricks like long-polling.
However, TCP is just byte stream. You have to find another protocol over it to define your messages. You can use Google's ProtoBuffer for that.
Use HTTP if you need the services it provides -- e.g., message framing, caching, redirection, content metadata, partial responses, content negotiation -- as well as a large number of well-understood tools, implementations, documentation, etc.
Use TCP if you can't work within those constraints. However, if you use TCP you'll be creating a new application protocol, which has a number of pitfalls.

How to implement a bidirectional "mailbox service" over tcp?

The idea is to allow to peer processes to exchange messages (packets) over tcp as much asynchronously as possible.
The way I'd like it to work is each process to have an outbox and an inbox. The send operation is just a push on the outbox. The receive operation is just a pop on the inbox. Underlying protocol would take care of the communication details.
Is there a way to implement such mechanism using a single TCP connection?
How would that be implemented using BSD sockets and modern OO Socket APIs (like Java or C# socket API)?
Yes, it can be done with a single TCP connection. For one obvious example, (though a bit more elaborate than you really need) you could take a look at the NNTP protocol (RFC 3977). What you seem to want would be similar to retrieving and posting articles.

Resources