Question
Suppose I open websocket connections /A, /B and /C from one client to the same server, and messages are constantly being sent by the client on each ws connection.
If the packet carrying a message for ws connection /A times out and ends up needing to be being retransmitted in the underlying TCP layer, is there any chance that this will impact messages being transmitted by the client on ws connections /B and /C, in the way that multiple packets being sent over a single TCP connection will be delayed when an earlier one times out?
Or is there a chance that each ws connection receives its own TCP connection and so any congestion on one does not impact the packets carrying messages on the others? Could it be implementation-specific?
Overview
After an initial handshake over HTTP, Websockets send their data over a TCP/IP connection.
My assumptions regarding TCP Connections:
For a specific TCP connection on a given port, the connection makes the guarantee that all packets sent by the a sender through it will be received by the receiver, and will do so in order. It is a reliable ordered connection.
This means if two packets are sent over a TCP connection by the sender and the first one does not arrive within a given timeout, the second one is delayed until the first one has been successfully retransmitted by the sender. As far as the receiver is concerned, they always see packet one, then two.
If you create two separate TCP connections on two separate ports, then packets lost on one connection naturally have no impact on packets on the other connection. The reliable ordered guarantee only applies to the packets within one TCP connection, not all of them.
Since an active websocket connection runs on top of a TCP connection, are there any assumptions we can make when we open multiple parallel websocket connections between the same client and server?
If I have a websocket javascript client opening two or more websocket connections to the same server, does the underlying implementation use only a single TCP connection?
Is there a chance that this may be implementation-specific, or is it simply guaranteed that for a given websocket server all connections will occur on the same underlying TCP connection?
Context
The context here is a networked multiplayer game in the browser, where the desired behavior would be to have multiple parallel data streams where any timeout or latency on one stream has no impact on the packets sent on the others.
Of course when low latency is desirable for multiplayer games you generally want to use UDP instead of TCP, but there is no real cross-browser, well supported option currently for that that I am aware of. In an environment where UDP sockets are an option you would implement your own data streams with varying reliability/order guarantees on top of UDP.
However UDP-like low latency when it comes to one packet not blocking another can be achieved by guaranteeing that a TCP connection only ever has one packet in flight, and using more connections to allow in-parallel packets (source). Naturally that loses out on some optimizations, but may be desirable if latency is the primary variable being optimized for.
Related
How long do NAT routers typically allow incoming packets from previously opened TCP streams before rejecting packets? I'm working on a P2P application and I'd rather not keep an open connection to my central server and relay packets. Instead I was thinking of having the clients poll the central server, save those ip and port numbers and reach back out to each client from server to initiate P2P connection at some later time. If NAT allows packets in for a long time this is feasible. If this is not possible does anyone know how other P2P applications establish NAT Transveral/Connections?
That's unlikely to work. Typical home routers will track the state of TCP connections, and will not forward traffic on connections that have already closed.
Even for active TCP connections, the amount of time that routers will retain connections that are open, but not sending any data, can vary wildly -- I've seen everything between a minute and a week. You will need to keep the connection open, and send periodic keep-alives, to reliably maintain a connection.
Some routers also support the NAT Port Mapping Protocol to forward ports to a device behind the router. This is not universally supported, though. In particular, it is almost never supported in business routers.
I have an application consisting of client and server by making use of sockets.
On the server side in the thread where it is receiving messages from client i have made a sleep call for 10 sec.Now when i send messages from client 1000000 times to server then messages being received from server is very slowly.My question is as follows:
-Does it mean that the receiving call on server side is blocking call?
-Secondly,is there any good document which can make me understand better the blocking and non blocking behavior of send and receive call of sockets.
Depends on whether you're using TCP or UDP sockets. TCP guarantees delivery, UDP doesn't. So in a UDP application packets can be dropped for any number of reasons, including if the servers sends too quickly to the client.
By default, calls on sockets are blocking calls. You have to set non-blocking explicitly.
This question already has answers here:
What is the fundamental difference between WebSockets and pure TCP?
(4 answers)
Closed 4 years ago.
Trying to understand as best as I can the differences between TCP socket and websocket, I've already found a lot of useful information within these questions:
fundamental difference between websockets and pure TCP
How to establish a TCP Socket connection from a web browser (client side)?
and so on...
In my investigations, I went through this sentence on wikipedia:
Websocket differs from TCP in that it enables a stream of messages instead of a stream of bytes
I'm not totally sure about what it means exactly. What are your interpretations?
When you send bytes from a buffer with a normal TCP socket, the send function returns the number of bytes of the buffer that were sent. If it is a non-blocking socket or a non-blocking send then the number of bytes sent may be less than the size of the buffer. If it is a blocking socket or blocking send, then the number returned will match the size of the buffer but the call may block. With WebSockets, the data that is passed to the send method is always either sent as a whole "message" or not at all. Also, browser WebSocket implementations do not block on the send call.
But there are more important differences on the receiving side of things. When the receiver does a recv (or read) on a TCP socket, there is no guarantee that the number of bytes returned corresponds to a single send (or write) on the sender side. It might be the same, it may be less (or zero) and it might even be more (in which case bytes from multiple send/writes are received). With WebSockets, the recipient of a message is event-driven (you generally register a message handler routine), and the data in the event is always the entire message that the other side sent.
Note that you can do message based communication using TCP sockets, but you need some extra layer/encapsulation that is adding framing/message boundary data to the messages so that the original messages can be re-assembled from the pieces. In fact, WebSockets is built on normal TCP sockets and uses frame headers that contains the size of each frame and indicate which frames are part of a message. The WebSocket API re-assembles the TCP chunks of data into frames which are assembled into messages before invoking the message event handler once per message.
WebSocket is basically an application protocol (with reference to the ISO/OSI network stack), message-oriented, which makes use of TCP as transport layer.
The idea behind the WebSocket protocol consists of reusing the established TCP connection between a Client and Server. After the HTTP handshake the Client and Server start speaking WebSocket protocol by exchanging WebSocket envelopes. HTTP handshaking is used to overcome any barrier (e.g. firewalls) between a Client and a Server offering some services (usually port 80 is accessible from anywhere, by anyone). Client and Server can switch over speaking HTTP in any moment, making use of the same TCP connection (which is never released).
Behind the scenes WebSocket rebuilds the TCP frames in consistent envelopes/messages. The full-duplex channel is used by the Server to push updates towards the Client in an asynchronous way: the channel is open and the Client can call any futures/callbacks/promises to manage any asynchronous WebSocket received message.
To put it simply, WebSocket is a high level protocol (like HTTP itself) built on TCP (reliable transport layer, on per frame basis) that makes possible to build effective real-time application with JS Clients (previously Comet and long-polling techniques were used to pull updates from the Server before WebSockets were implemented. See Stackoverflow post: Differences between websockets and long polling for turn based game server ).
What are the performance considerations that one should take into account when designing a server application that listens on one port? I know that it is possible for many thousands of clients to connect to a server on a single port, but is performance negatively affected by having the server application accept all incoming requests on a single port?
Is my understanding correct that this model (server listening on one port which handles incoming connections, and then responds back over the outbound connection that was created when the client connection was established) is the way databases/webservers etc work?
Regards,
Brian
It does not matter if the server listens on one port or multiple ports. The server still has to establish a full socket connection for each client it accepts. The OS still has to route inbound packets to the correct socket endpoints, and sockets are uniquely identified by the combination of IP/Port pairs of both endpoints, so there is no performance issues if the server endpoints use different ports.
Any performance issues are going to be in the way the server's code handles those socket connections. If it only listens on one port, and accepts clients on that port using a simple accept() loop in a single thread, then the rate that it can accept clients is limited by that loop. Typically, servers spawn worker threads for each accepted client, which in itself has performance overhead of its own if thread pooling is not used. If the server needs to handle a lot of clients simultaneously, then it should use overlapped I/O or I/O Completion Ports to handle the connections more efficiently.
For an UDP server architecture that will have long-lived connections, one architecture is to have one socket that listens to all incoming UDP traffic, and then create separate sockets for each connection using connect() to set the remote address. My question is whether it is possible to do this atomically similar to what accept() does for TCP.
The reason for creating a separate socket and using connect() is that this makes it easy to spread the packet-processing across multiple threads, and also make it easier to have the socket directly associated with the data structures that are needed for processing.
The demultiplexing logic in the networking stack will route the incoming packets to the most specific socket.
Now my question is basically what happens when one wants to emulate accept() for UDP like this:
Use select() with a fd-set that includes the UDP server-socket.
Then read a packet from the UDP server-socket.
Then create a new UDP socket which is then connect()ed to the remote address
I call select() with a fd-set that includes both sockets.
What is returned?
given that a packet arrives to the OS somewhere between 1 and 3.
Will the packet be demultiplexed to the UDP server-socket, or will it be demultiplexed to the more specific socket created in 3. That is, at what point does demultiplexing take place? When the packet arrives, or must it happen "as if" it arrived at point 4?
Follow-up question in case the above does not work: What's the best way to do this?
I see that this discussion is from 2009, but since it keeps popping up when I search, I thought I should share my approach. Both to get some feedback and because I am curios about how the author of the question solved the problem.
The way I chose emulate UDP-accept was a combination of number one and two in nik's answer. I have a root thread which listens on a given socket. I have chosen to use TCP for simplicity, but changing this socket to UDP is not very hard. When a client wants to "connect" to my server using UDP, it first connects to the TCP socket and requests a new connection.
The root thread then proceeds by creating a UDP socket, binds it to a local interface, does connect and sets up data structures. This file descriptor is then passed to the thread that will be responsible for the connection. The IP/port information of the new UDP socket is passed back to the client, which creates a new UDP socket and sends data to the provided IP/port.
This approach works well for my use, but the additional steps for setting up a flow introduces an overhead. In some cases, this overhead might not be acceptable.
I found this question after asking it myself here...
UDP server and connected sockets
Since connect() is available for UDP to specify the peer address, I wonder why accept() wasn't made available to effectively complete the connected UDP session from the server side. It could even move the datagram (and any others from the same client) that triggered the accept() over to the new descriptor.
This would enable better server scalability (see the rationale behind SO_REUSEPORT for more background), as well as reliable DTLS authentication.
This will not work.
You have two simple options.
Create a multi-threaded program that has a 'root' thread listening on the UDP socket and 'dispatching' received packets to the correct thread based on the source. This is because you want to segregate processing by source.
Extend your protocol so the the sources accept an incoming connection on some fixed port and then continue with the protocol communication. In this case you would let the source request on the standard UDP port (of your choice), then your end will respond from a new UDP socket to the sources' UDP port. This way you have initiated a new UDP path from your end backwards to the known UDP port of each source. That way you have different UDP sockets at your end.