Intended Audience
This article is written by a software developer for anyone who is interested in the technical aspects of modern web browsers. Readers do not need any pre-knowledge to understand the content of the article. All you need to know is overview of browser (Browser Fundamentals | Part-2) and basics of HTML & CSS.
Content
- Introduction
- How Browser Connect to the Internet?
- Connection Protocols - TCP/UDP
- Connection Adaptor - Sockets
- Why Browser Limit Socket Connections?
- Lifecycle of sockets
Introduction
We all have used the modern web browsers to some extent (more or less). We use it to watch our favourite movies, games, chatting and what not. But there is one thing without with browser is completely useless (at least due to pupose for which it was created). That thing is it's ability to connect to the Internet. Yes our own world wide web. This raises a curiosity about how this is accomplished? How browsers connects itself to the Internet. In this article we will dig deep into this.
How Browser Connect to the Internet?
Lets view it from top level. On one side we have the Internet, and on the other side we have the browser. As we can see, there is a difference in the language thay both speak. The Internet (Network) understands only TCP/UDP. These are transport layer protocols (language) to handle how the data is transported between server and client (browser). Whereas a browser understands HTTP. HTTP is an application layer protocol (language) to recieve/send hypertexts from/to a server. Hypertexts are kind of data that browser needs for its application usage.
Who will compromise?
Here, both browser & the Internet is kind of rigid on the protocols they uses, and they has their own reasons. To make both work with each other, we are three possible options:
- The Internet implements an adaptor that translates between HTTP and TCP/UDP.
- Browser implements an adaptor that translates between HTTP and TCP/UDP.
- Both implements an adaptor that translates to a new common language that both understands.
Connection Protocols - TCP/UDP
These transport layer protocols are the bus that a data packet (smallest unit of transferrable unit) must board to get from one machine to another around the world. This data packet can be from HTTP, RTCPeerConnection, etc. TCP & UDP, both does the same job, the difference is in how they do it.
Feature |
TCP |
UDP |
Connection status |
Requires an established connection to transmit data (connection should be closed once transmission is complete) |
Connectionless protocol with no requirements for opening, maintaining, or terminating a connection |
Data sequencing |
Able to sequence |
Unable to sequence |
Guaranteed delivery |
Can guarantee delivery of data to the destination router |
Cannot guarantee delivery of data to the destination |
Retransmission of data |
Retransmission of lost packets is possible |
No retransmission of lost packets |
Error checking |
Extensive error checking and acknowledgment of data |
Basic error checking mechanism using checksums |
Method of transfer |
Data is read as a byte stream; messages are transmitted to segment boundaries |
UDP packets with defined boundaries; sent individually and checked for integrity on arrival |
Speed |
Slower than UDP |
Faster than TCP |
Broadcasting |
Does not support Broadcasting |
Does support Broadcasting |
Optimal use |
Used by HTTPS, HTTP, SMTP, POP, FTP, etc |
Video conferencing, streaming, DNS, VoIP, etc |
Connection Adaptor - Sockets
The TCP/UDP adaptor we talked in previous sections, is nothing but TCP/UDP Sockets. It opens a door way to the Internet and helps browser to communicate across the world. But for this, every browser need to implement and expose an API to create TCP/UDP sockets. And of course, there is a standard set by W3C organisation. Here is an example of how TCPSocket should be invoked according to the standard.
- First create a new TCPSocket object.
- Check for permission, and if not throw SecurityError.
- If the provided host is invalid, throw, InvalidAccessError.
- and many more...
Following the standard, chrome exposes the API and it is something like below:
chrome.sockets.tcp.create(properties?: SocketProperties, callback: function)Here is the detailed design of chrome socket API: https://docs.google.com/document/d/1Xa5nFkIWxkL3hZHvDYWPhT8sZvNeFpCUKNuqIwZHxnE/edit Theoretically it is possible to create as many number of sockets as possible. But browsers imposes some upper limit to optimize the resource and performance. Chrome limits the socket creation as per the origin. It imposes a restriction of six sockets per origin. https://source.chromium.org/chromium/chromium/src/+/master:net/socket/client_socket_pool_manager.cc;l=51
Why Browser Limit Socket Connections?
The reason why browser imposes a limit is because the servers could not be oveloaded by small number of browsers and end up classifying user as DDoS attacker.
Also, according to IETF standards followed by browsers states that browsers should limit the number of simultaneous connections. Here is the reasoning behind it:
Clients SHOULD limit the number of simultaneous connections that they
maintain to a given server.
Previous revisions of HTTP gave a specific number of connections as a
ceiling, but this was found to be impractical for many applications.
As a result, this specification does not mandate a particular maximum
number of connections, but instead encourages clients to be
conservative when opening multiple connections.
Multiple connections are typically used to avoid the "head-of-line
blocking" problem, wherein a request that takes significant server-
side processing and/or has a large payload blocks subsequent requests
on the same connection. However, each connection consumes server
resources. Furthermore, using multiple connections can cause
undesirable side effects in congested networks.
Note that servers might reject traffic that they deem abusive,
including an excessive number of connections from a client.
Previously, browsers had the common limit of only 2 connections. This may be sufficient in the beginning day of web pages as most of the contents are delivered in a single page load. However, it soon become the bottleneck when css, javascript getting popular. Because of this, companies started to increase this limit for modern browsers.
Lifecycle of sockets
Sockets follows a defined processes in its lifetime. From creation to close, there are various processes that helps accomplishing the task of communication.
Create
This stage creates a TCP/UDP socket according to provided options, passed as SocketProperties, in which you can pass {buffer: 4096, name: "my_socket", persistent: false}. TCP client :
chrome.sockets.tcp.create( properties?: SocketProperties, callback: (createInfo: CreateInfo) => void, )TCP server :
chrome.sockets.tcpServer.create( properties?: SocketProperties, callback: (createInfo: CreateInfo) => void, )Once the socket is created, the passed callback is called with CreateInfo as parameter. This parameter is an object with contains socketId as a key. This socketId uniquely identifies the newly created socket.
Connect
Using the socketId created in previous step we can connect to remote machine with peerAddress & peerPort.
chrome.sockets.tcp.connect( socketId: number, peerAddress: string, peerPort: number, callback: function, )The callback is to signal that socket is now connected to the remote machine at provided address. This callback is called with a number parameter indicating success/error.
Send
If the created socket is the TCP server, we can send the data to desired remote machine.
chrome.sockets.tcp.send( socketId: number, data: ArrayBuffer, callback: function, )And to get notified of send acknowledgement, we also have a callback function which is called with parameter, SendInfo.
onReceive/onReceiveError Events
These are the events when any data arrives at the connected socket. These events are available on both TCP client and server.
onReceive event raised when data has been received for a given socket.
onReceiveError event raised when a network error occured while the runtime was waiting for data on the socket address and port. Once this event is raised, the socket is set to paused and no more onReceive events are raised for this socket.
onReceive/onReceiveError Event Listeners
To use onReceive/onReceiveError events, first we need to register it. Below are the way to register them. onReceiveListener
chrome.sockets.tcp.onReceiveError.addListener( callback: function, )The callback of this event is called with ReceiveInfo object which contains the data & the socketId. onReceiveErrorListener
chrome.sockets.tcp.onReceive.addListener( callback: function, )The callback of this event is called with ReceiveInfo object which contains the resultCode & the socketId.
Disconnect
This is also present on both TCP client and server. This method disconnects the socket from the remote machine. Still the socket is not destroyed yet. We can re-use this socket for another connection. TCP client :
chrome.sockets.tcp.disconnect( socketId: number, callback?: function, )TCP server :
chrome.sockets.tcpServer.disconnect( socketId: number, callback?: function, )The callback is called with zero parameters.
Close
This is the final stage in any socket's lifetime. This methos does two jobs - disconnect & destroys the socket. TCP client :
chrome.sockets.tcp.close( socketId: number, callback?: function, )TCP server :
chrome.sockets.tcpServer.close( socketId: number, callback?: function, )The callback is called with zero parameters.
Links & References
- https://www.lifesize.com/en/blog/tcp-vs-udp/
- https://www.w3.org/TR/tcp-udp-sockets
- https://developer.chrome.com/docs/extensions/reference/sockets_tcp/
- http://sgdev-blog.blogspot.com/2014/01/maximum-concurrent-connection-to-same.html
About Author
I love to shape my ideas into a reality. You can find me either working on a project or having a beer with my close friend. :-)