TCP Server With the SwiftNIO Networking Framework

Mobile developers often work with REST APIs or other networking protocols in their applications to access data or to coordinate activities. In this tutorial you will create a Swift Server with SwiftNIO, a low-level networking framework that makes creating TCP servers easier than before. By David Okun.

Leave a rating/review
Download materials
Save for later
Share

Mobile developers often work with REST APIs or other networking protocols in their applications — whether it’s to retrieve data, communicate with other devices, or something else. SwiftNIO, written by Apple, is a low-level networking framework that makes writing Swift servers even easier than before, empowering Swift developers to leverage their skills on the server side.

In this tutorial, you’ll:

  • Learn about what purpose SwiftNIO serves and why Apple made and open-sourced it.
  • Practice working within a SwiftNIO framework by creating a Quote Of The Day Swift TCP server that you’ll connect to using a provided iOS app.

To start, you’ll need a Mac running at least macOS 10.12 Sierra with Xcode 9.3 or later. You’ll also use the command line, so be sure to open up Terminal, and check the command line utility for Swift is installed. You can check this by entering swift –version. It must be version 4.1 or later.

Note: The command line tool you need should be installed with Xcode. If you don’t successfully see your version of Swift when running the swift –version command, go here for more information.

Getting Started

First, it’s helpful to understand exactly how the SwiftNIO framework differs from other Swift frameworks.

Swift-on-the-Server Status Quo

If you’re a Swift developer, it’s very likely you’ve focused only on mobile applications. This makes servers in the cloud seem like voodoo magic — or at least a little confusing at first.

I don’t get you, cloud.

SwiftNIO

Thankfully, if you know Swift, frameworks like Kitura and Vapor make writing a web service easier.

However, these frameworks operate as a convenient layer on top of some sophisticated and low-level socket networking code, much of which interoperates with C. In the case of Kitura, once Swift became open sourced and available for Linux, IBM wrote BlueSocket to serve as its low-level socket networking layer.

How SwiftNIO Differs
SwiftNIO

You complete me, NIO.

You complete me, NIO.

SwiftNIO

BlueSocket is great, but it doesn’t fill in all the blanks when it comes to server-side Swift. For example, Kitura not only included the work of BlueSocket, but it also implemented the entire HTTP stack under the hood, so incoming communication would be routed the right way. Now, Apple has raised the bar, introducing SwiftNIO and essentially handling socket communication and HTTP for us.

Note: SwiftNIO has been written as a port of Netty, a Java low-level networking framework, but in Swift.

This is a diagram taken from Norman Maurer’s talk on SwiftNIO, given March 1, 2018, in Tokyo.

This tutorial won’t go into great detail about every piece of the above diagram but, as you work your way through, each piece should begin to make sense. However, it’s worth explaining what an EventLoopGroup is and, thus, what a MultiThreadedEventLoopGroup accomplishes with this class.

EventLoopGroup and MultiThreadedEventLoopGroup

An EventLoop runs in a loop, looking for new tasks to handle that have come in from a new client via a network connection. Think of an EventLoop like a serial DispatchQueue, which allows you to delegate blocks of code for execution at a time of your choosing. As multiple EventLoop instances cycle through your thread, they look for tasks to execute.

After an EventLoop searches for tasks and schedules them, it executes them one by one.

When you put these EventLoop instances into an EventLoopGroup, the handler looks more like a concurrent DispatchQueue. You can also think of this like a thread pool. This means you can submit multiple tasks to the group and, depending on the time it takes to complete each task, the order of completed tasks may not be what you initially submitted to the group.

This is where the MultiThreadedEventLoopGroup class comes in. This specifies the EventLoopGroup that’s created will tie each group to a specific thread, further streamlining your asynchronous operations that come in. Think of it like an upgraded EventLoopGroup.

Each task gets taken care of in its own discrete group.

Synchronous/Asynchronous Example

Let’s say you’re at a food truck operated by one person. The person at the front of the line orders his food. He pays; he waits. He gets his food. The next person repeats this same process. The food truck delivers everyone’s order correctly, but it’s very slow. If you’re at the end of the line, you are pretty unhappy.

This is an example of a synchronous operation — something that blocks all other work until the current request is completed. A connection to a PostgreSQL database is another example.

Now, imagine the same food truck has an order-taker and two chefs. The person at the front of the line orders his food. He pays; he waits. But wait! The second person can now order his food without having to wait for the operator to complete the order for the first person. And the first person only has to wait for one other person. Here, the chefs are the EventLoopGroups making the food.

This is an example of a set of asynchronous operations. Ultimately, you’re waiting on the available resources of the service. But this new setup can handle multiple requests at the same time. The end user will see an increase in performance.

Another example of this is… well, SwiftNIO!

Setting Up Quote of the Day

To kick things off, download the materials for this tutorial; you can find a link at the top or bottom of this tutorial. You’ll be implementing a server called Quote of the Day — believe it or not, Quote of the Day (QOTD) is a real internet standard (RFC). You can read the protocol spec here.

The flow of information from the server works as follows:

  • Open a TCP connection upon request.
  • Write a random quote to the response.
  • Send the response.
  • Close the connection.

If you take a look at the RFC for Quote of the Day, you’ll notice two key things that you’ll do differently in this tutorial:

  1. You’ll use port 1717 instead of 17. Port 17 is locked down, requiring root permissions on macOS.
  2. You’ll only create a TCP/IP connection, not a UDP connection. As of this writing, UDP is still a work-in-progress on SwiftNIO (so many acronyms!).

For this tutorial, you’ll also use an iOS client to check that the server works properly. This iOS client uses BlueSocket — you won’t be making any changes to the iOS app, but feel free to look through the source code on your own.

Note: SwiftNIO also has the ability to act as a client for network communication and not just as a server. This means you could, in theory, write an iOS client using SwiftNIO, too.