In the previous series of posts we largely operated at the level of the Unix calls. While some higher level consideration were mentioned it those too aimed at implementation details.
Since then, I have been working on a package (called SwifterSockets) which I hope to present soon as an open source project. Before I can do that I have to clarify some thoughts related to making connections between computers, and what better way to achieve this than to write about it?
In this post I want to explore the client side.
What kind of connections can a client make?
As I see it, there are a couple of possibilities:
- Open - Transmit - Close
- Open - Transmit - Receive - Close
- Open - Transmit - Close - Open - Receive - Close
- Open - Transmit - Transmit - Close
- Open - Transmit - Receive - Transmit - Receive - Close
Notice that when I talk about "open" and "close" I am assuming that this is all done by the client. Possible server malfunctions that close the connection are not considered. Also, the TCP/IP level guarantees that the data is received correctly (in both directions) so no worries there, but the transfer may be incomplete or time-out. In a real life application you will need to design for those possibilities as well, but they are considered out of scope for this article.
1. Open - Transmit - Close
This is the easiest case, the connection is opened and once all data is transmitted the connection is closed. The server accepts the data and knows the data is complete when the connection is closed or by examining the contents of the transmitted data. This type of connection is best for situations where a client sporadically needs to transfer some data to a server.
2. Open - Transmit - Receive - Close
This is a little more interesting, the client needs a response from the server, so after transmitting the its data (often a request for information) it will wait
on the same connection (i.e. socket) for the reply of the server. This places an extra demand on the data that is transmitted, it must include a mechanism by which the server side can determine that the data is received completely. In general this means that some kind of protocol must be implemented that either terminates by using a special byte(-sequence) or the data must be structured (like for example JSON or XML) or it must includes a length cq size field (like an HTTP request or message). This type of connection is used a lot, most browser sessions will use this, and many web services will use this as well. There is slight overhead associated with opening and closing the connection every time a new transfer/receive cycle is needed though. Which makes it slightly less efficient that option 5, but it also makes the whole process of communication between client and server more robust.
3. Open - Transmit - Close - Open - Receive - Close
This is mentioned for completeness only. It is probably not used a lot as it requires a meta protocol higher than the actual data structure. However if security is a problem, then this is worth considering as most attacks will assume that option 2 or 5 are used. On the other hand if security is really a problem, then use option 1 in both directions. I.e. both sides implement a client and server side. When a client transmits data to a server, the server will reply
as a client (using option 1). This has the advantage that the server will (in most cases) reply to known clients only and it would need a hardware attack in addition to the software attack to intercept the replies.
4. Open - Transmit - Transmit - Close
Like option 2, the data that is transmitted must be structured in such a way that the server knows how to differentiate between the data transmissions. See option 2 for the available methods. This type of connection is used when the data has to be transferred often enough so that it is advantageous to keep the connection open. However if data corruption is possible, then it can also lead to loss of data due to de-synchronization, depending on the method used to differentiate between data transmissions. If desynchronisation is a possibility then an analysis must be made as to the tolerable loss of data. Once that limit is exceeded, the connection must be closed and re-opened. I.e. if it is tolerable to lose at most 10 data transmissions, then automatically close the connection after 10 transmissions and reopen the connection afterwards.
In addition, if the data transfer has burst characteristics a timeout for inactivity may be useful. I.e. if data is transmitted for - say 10 minutes and then ceases for an hour, it is probably a good idea to implement on the server an inactivity timeout of 11 minutes after which the server closes the connection. The client side should then reopen the connection whenever necessary.
This type of connection is useful for monitoring and recording.
5. Open - Transmit - Receive - Transmit - Receive - Close
Much of the discussion of option 4 also applies to option 5. This type of connection is often used in monitoring & control. Like option 4 an activity timeout should be considered, and a data-loss analyses must be performed if desynchronisation due to data corruption is a possibility. Keep in mind that every open connection uses valuable resources on the server. If a server has to be able to accept connections from many different clients it is simply not acceptable to keep all connections open as eventually the server will run out of resources.
It is necessary to weigh the efficiency of keeping a connection open against the cost of consuming resources and find an optimal solution.
For example: While most http clients (browsers) will want to keep a connection alive, a server cannot honour these requests indefinitely as eventually the server will run out of resources and would be unable to accept new clients (browsers).
So far the client side, in the
next post I will clarify my thoughts about the server side implications.
Check out my
Port Spy app in the App Store. A utility that helps you debug your socket based application and includes its own source code. So you can see first hand how to implement socket based io in Swift. And you will be helping this blog!
Happy coding...
Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH
We don't get the world we wish for... we get the world we pay for.