{"id":2390,"date":"2016-01-03T11:54:11","date_gmt":"2016-01-03T17:54:11","guid":{"rendered":"http:\/\/dev.iachieved.it\/iachievedit\/?p=2390"},"modified":"2020-07-18T18:22:51","modified_gmt":"2020-07-18T23:22:51","slug":"tcp-sockets-with-swift-on-linux","status":"publish","type":"post","link":"https:\/\/dev.iachieved.it\/iachievedit\/tcp-sockets-with-swift-on-linux\/","title":{"rendered":"TCP Sockets with Swift on Linux"},"content":{"rendered":"<p>A long time ago in a galaxy far, far away, software developers wrote client-server applications with <a href=\"https:\/\/en.wikipedia.org\/wiki\/Transmission_Control_Protocol\">TCP\/IP<\/a> <a href=\"https:\/\/en.wikipedia.org\/wiki\/Network_socket\">sockets<\/a>.  That was before the dark times, before <a href=\"https:\/\/en.wikipedia.org\/wiki\/Hypertext_Transfer_Protocol\">HTTP<\/a>.<\/p>\n<p>I am of course, joking.  HTTP can be leveraged to provide a wide variety of client-server applications and is of course at the base of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Representational_state_transfer\">REST<\/a> applications.  What HTTP brings to the table though is not the plumbing to get packets on the wire, but an agreed upon protocol structure (and to some degree a standard as to what port is being used) for those packets.  Action verbs such as GET, POST, PUT, etc. and the HTTP header itself are what makes HTTP ideal for developing client-server applications.<\/p>\n<p>In the end though, at the bottom of the stack, bits and bytes are marshaled through your operating system&#8217;s <a href=\"http:\/\/man7.org\/linux\/man-pages\/man2\/socket.2.html\">socket interface<\/a>.  The API for interacting with network sockets is quite rich and many a <a href=\"http:\/\/gnosis.cx\/publish\/programming\/sockets.html\">tutorial<\/a> and <a href=\"http:\/\/www.amazon.com\/TCP-Illustrated-Protocols-Addison-Wesley-Professional\/dp\/0321336313\">books<\/a> have been written on the topic.  IP networking routines in C can be considerably verbose, and were one of the first &#8220;real-world&#8221; APIs encapsulated in object-oriented routines with C++.  That tradition continued with Foundation&#8217;s <a href=\"https:\/\/developer.apple.com\/library\/mac\/documentation\/Cocoa\/Conceptual\/Streams\/Articles\/NetworkStreams.html\"><code>CFStream<\/code><\/a> class and now our Swift <code>swiftysockets<\/code> API.<\/p>\n<h2>Swiftychat<\/h2>\n<p>To illustrate how to use TCP\/IP network sockets with Swift, we&#8217;ll be developing Swiftychat, a basic &#8220;chat system&#8221; application.  It&#8217;s quite a naive application, limited in functionality, and would stand no chance in being used in the real world, but, even still, it&#8217;s a working example of how to send and receive strings on TCP\/IP sockets in Swift.<\/p>\n<h3>swiftysockets<\/h3>\n<p>Swiftychat will make use of <a href=\"https:\/\/github.com\/iachievedit\/swiftysockets\">swiftysockets<\/a>, a Swift Package Manager-ready TCP\/IP socket implementation that was originally developed by the <a href=\"https:\/\/github.com\/zewo\">Zewo<\/a> team.  Unfortunately due to packaging constraints we have to do a little bit of a dance first to get an underlying C library, <a href=\"https:\/\/github.com\/iachievedit\/Tide\">Tide<\/a>, installed on our system.  So let&#8217;s do that now.<\/p>\n<pre class=\"crayon:false\">\n$ git clone https:\/\/github.com\/iachievedit\/Tide\nCloning into 'Tide'...\n...\n$ cd Tide\n$ sudo make install\nclang -c Tide\/tcp.c Tide\/ip.c Tide\/utils.c\nar -rcs libtide.a *.o\nrm *.o\nmkdir -p tide\/usr\/local\/lib\nmkdir -p tide\/usr\/local\/include\/tide\ncp Tide\/tcp.h Tide\/ip.h Tide\/utils.h Tide\/tide_swift.h tide\/usr\/local\/include\/tide\n# copy .a\ncp libtide.a tide\/usr\/local\/lib\/\nmkdir -p \/usr\/local\ncp -r tide\/usr\/local\/* \/usr\/local\/\n<\/pre>\n<p>At some point we believe the Swift Package Manager <a href=\"https:\/\/github.com\/ddunbar\/swift-evolution\/blob\/master\/proposals\/NNNN-swiftpm-c-language-targets.md\">will be able to compile C libraries<\/a> that can be linked against in the rest of your package build.  Until then, this is the best we can do.<\/p>\n<p>Once Tide is installed we can leverage swiftysockets in our Swiftychat apps.<\/p>\n<h3>Start Coding!<\/h3>\n<p>Our <code>main.swift<\/code> file is as simple as it gets.  Create a <code>ChatterServer<\/code> and <code>start<\/code> it.<\/p>\n<p><code>main.swift<\/code><\/p>\n<pre class=\"lang:swift\">\nif let server = ChatterServer() {\n  server.start()\n}\n<\/pre>\n<p>Of course, a brief <code>main.swift<\/code> can only mean one thing.  Invasion.  Oh wait, I&#8217;m done with the Star Wars references.<\/p>\n<p>A brief <code>main.swift<\/code> means our implementation is tucked away in the <code>ChatterServer<\/code> class, which looks like this:<\/p>\n<p><code>ChatterServer.swift<\/code>:<\/p>\n<pre class=\"lang:swift\">\nimport swiftysockets\nimport Foundation\n\nclass ChatterServer {\n\n  private let ip:IP?\n  private let server:TCPServerSocket?\n\n  init?() {\n    do {\n      self.ip     = try IP(port:5555)\n      self.server = try TCPServerSocket(ip:self.ip!)\n    } catch let error {\n      print(error)\n      return nil\n    }\n  }\n\n  func start() {\n    while true {\n      do {\n        let client = try server!.accept()\n        self.addClient(client)\n      } catch let error {\n        print(error)\n      }\n    }\n  }\n\n  private var connectedClients:[TCPClientSocket] = []\n  private var connectionCount = 0\n  private func addClient(client:TCPClientSocket) {\n    self.connectionCount += 1\n    let handlerThread = NSThread(){\n      let clientId = self.connectionCount\n      \n      print(\"Client \\(clientId) connected\")\n      \n      while true {\n        do {\n          if let s = try client.receiveString(untilDelimiter: \"\\n\") {\n            print(\"Received from client \\(clientId):  \\(s)\", terminator:\"\")\n            self.broadcastMessage(s, except:client)\n          }\n        } catch let error {\n          print (\"Client \\(clientId) disconnected:  \\(error)\")\n          self.removeClient(client)\n          return\n        }\n      }\n    }\n    handlerThread.start()\n    connectedClients.append(client)\n  }\n\n  private func removeClient(client:TCPClientSocket) {\n    connectedClients = connectedClients.filter(){$0 !== client}\n  }\n\n  private func broadcastMessage(message:String, except:TCPClientSocket) {\n    for client in connectedClients where client !== except {\n      do {\n        try client.sendString(message)\n        try client.flush()\n      } catch {\n        \/\/ \n      }\n    }\n  }\n}\n<\/pre>\n<p>Breaking down our server we have:<\/p>\n<p><b>1.<\/b>  Initialization<\/p>\n<p>We make use of the <code>init?<\/code> initializer to signal that <code>nil<\/code> is a possible return value since both the <code>IP<\/code> and <code>TCPServerSocket<\/code> classes (from swiftysockets) can throw an error.  <code>IP<\/code> encapsulates our IP address and port information nicely and we provide an instance of it to the <code>TCPServerSocket<\/code> initializer.  If <code>init<\/code> succeeds we now have TCP socket on the given port ready to accept incoming connections.<\/p>\n<p><b>2.<\/b>  The Main Loop<\/p>\n<p>Name the function <code>startListening<\/code>, <code>start<\/code>, <code>main<\/code>, we don&#8217;t care.  It is the main event loop that accepts new client connections (<code>server!.accept()<\/code>) and adds them to the list of connected clients.  <code>server!.accept()<\/code> is a blocking function that hangs out and waits for new connections.  Pretty standard stuff.<\/p>\n<p><b>3.<\/b>  Client Management<\/p>\n<p>The rest of the <code>ChatterServer<\/code> contains all of the &#8220;client management&#8221; functions.  There are a few variables and three routines that manage clients.<\/p>\n<p>Our variables are straightforward:<\/p>\n<ul>\n<li>an array of connected clients (`[TCPClientSocket]`)\n<li>a connection counter that is used to hand out a &#8220;client identifier&#8221;\n<\/ul>\n<p>The routines are straightforward as well:<\/p>\n<ul>\n<li>`addClient` takes a `TCPClientSocket`, increments our connection count, and then sets up an `NSThread` whose sole purpose is &#8220;manage&#8221; that given client&#8217;s connection.  As additional connections come in new `NSThread`s are created for them as well.  We&#8217;ll talk about the `NSThread` routine itself in a moment.  Once the thread is started `addClient` will then append the `TCPClientSocket` onto the end of the array of connected clients.\n<li>`removeClient` removes a client from the connected clients list using the `filter` function to &#8220;filter out&#8221; the given client.  Note here we use the `!==` <a href=\"https:\/\/developer.apple.com\/library\/ios\/documentation\/Swift\/Conceptual\/Swift_Programming_Language\/ClassesAndStructures.html\">identity operator<\/a>.\n<li>`broadcastMessage` is what makes the `ChatterServer` a chat server.  It uses the `where` keyword to create a filtered array that broadcasts a message created by a client to all of the other connected clients.  Again, we use the `!==` operator.\n<\/ul>\n<p>Recall that a thread is a separate execution path that runs inside the main process.  Our server creates a separate thread for each client that is connected.  Now, you can argue whether or not that is a good idea, and if we&#8217;re designing a server that will eventually handle tens of thousands of clients, I&#8217;d argue that it isn&#8217;t.  For our purposes though we&#8217;ll be fine.<\/p>\n<p>Looking once more at our thread:<\/p>\n<pre class=\"lang:swift\">\nlet handlerThread = NSThread(){\n      let clientId = self.connectionCount\n      \n      print(\"Client \\(clientId) connected\")\n      \n      while true {\n        do {\n          if let s = try client.receiveString(untilDelimiter: \"\\n\") {\n            print(\"Received from client \\(clientId):  \\(s)\", terminator:\"\")\n            self.broadcastMessage(s, except:client)\n          }\n        } catch let error {\n          print (\"Client \\(clientId) disconnected:  \\(error)\")\n          self.removeClient(client)\n          return\n        }\n      }\n    }\n    handlerThread.start()\n<\/pre>\n<p>Our client handling thread also sits in a loop waiting for input through the <code>receiveString<\/code> method of the <code>TCPClientSocket<\/code> class.  When a string is received the server logs it to the console and then broadcasts a response.  If the <code>try<\/code> results in an error (a disconnect) the server removes the client.<\/p>\n<h3>Putting it All Together<\/h3>\n<p>Our goal is to, as much as possible, use the Swift Package Manager for building our applications.  For an introduction to <code>swiftpm<\/code> check out our <a href=\"https:\/\/dev.iachieved.it\/iachievedit\/introducing-the-swift-package-manager\/\">tutorial<\/a>.<\/p>\n<p>Add the following to <code>Package.swift<\/code>:<\/p>\n<pre class=\"lang:swift\">\nimport PackageDescription\n\nlet package = Package(\n  name:  \"chatterserver\",\n  dependencies: [\n    .Package(url:  \"https:\/\/github.com\/iachievedit\/swiftysockets\", majorVersion: 0),\n  ]\n)\n<\/pre>\n<p>and in a directory named <code>Sources<\/code> add your <code>main.swift<\/code> and <code>ChatterServer.swift<\/code> code.<\/p>\n<p>Running <code>swift build<\/code> should download and build our two dependencies (<code>Tide<\/code> and <code>swiftysockets<\/code>) and compile our application code.  If all goes well you&#8217;ll have a binary named <code>chatterserver<\/code> in a directory named <code>.build\/debug\/<\/code>.<\/p>\n<h3>Testing it Out<\/h3>\n<p>Our next tutorial will be writing up a nifty little chat client, but for now we can test our server with the <code>nc<\/code> (<a href=\"https:\/\/en.wikipedia.org\/wiki\/Netcat\">netcat<\/a>) command.  Start your server and then in another terminal window type <code>nc localhost 5555<\/code>.  You should see in your server&#8217;s window <code>Client 1 connected<\/code>.  If you hit CTRL-C in your netcat &#8220;client&#8221; window the server will print a disconnect message along with the reason (like, <code>Connection reset by peer<\/code>).<\/p>\n<p>For the real test we&#8217;ll start up the server and three connected clients.<\/p>\n<figure id=\"attachment_2402\" aria-describedby=\"caption-attachment-2402\" style=\"width: 845px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2016\/01\/Selection_007.png\" rel=\"attachment wp-att-2402\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2016\/01\/Selection_007.png\" alt=\"Chatville\" width=\"845\" height=\"481\" class=\"size-full wp-image-2402\" \/><\/a><figcaption id=\"caption-attachment-2402\" class=\"wp-caption-text\">Chatville<\/figcaption><\/figure>\n<p>In the left-hand terminal our chat server is running.  On the right we have 3 clients, each started by typing the command <code>nc localhost 5555<\/code>.  As each client connects the server prints out a connection message.<\/p>\n<p>Recall that our <code>broadcastMessage<\/code> function excludes the originator of the message from the broadcast.  This prevents a client from receiving his own message back (take out the <code>where<\/code> clause and you will see what we mean).<\/p>\n<h3>What&#8217;s Next<\/h3>\n<p>Using <code>nc<\/code> as our client is a bit boring.  We can&#8217;t set a nickname, there&#8217;s no &#8220;structure&#8221; to our messages, no timestamps, etc.  In the above example someone receiving a message has no idea who was writing!  <code>swiftysockets<\/code> already has a <code>TCPClientSocket<\/code> class, why not create a more robust chat client?<\/p>\n<h2>Getting the Code<\/h2>\n<p>Of course we&#8217;ve put together the code for our little chat server <a href=\"https:\/\/github.com\/iachievedit\/swiftychatter\">here<\/a> on Github.  It also contains a <code>chatterclient<\/code> project which at the moment is not implemented.  If you start with the download, you can type <code>make<\/code> in the top-level directory and it will build both the client and server.  <b>Remember:<\/b> You must have installed <a href=\"https:\/\/github.com\/iachievedit\/Tide\"><code>libtide.a<\/code><\/a> and its associated headers <i>before<\/i> using <code>swiftysockets<\/code>!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A long time ago in a galaxy far, far away, software developers wrote client-server applications with TCP\/IP sockets. That was before the dark times, before HTTP. I am of course, joking. HTTP can be leveraged to provide a wide variety of client-server applications and is of course at the base of REST applications. What HTTP [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[19,5],"tags":[],"class_list":["post-2390","post","type-post","status-publish","format-standard","hentry","category-linux","category-swift"],"_links":{"self":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/2390"}],"collection":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/comments?post=2390"}],"version-history":[{"count":26,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/2390\/revisions"}],"predecessor-version":[{"id":4174,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/2390\/revisions\/4174"}],"wp:attachment":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/media?parent=2390"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/categories?post=2390"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/tags?post=2390"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}