Saturday, January 14, 2017

Using the BlueSocket framework to create an Echo client

In our last post we showed how to use the BlueSocket framework from IBM to create an echo server. In this post we will show how to use the same BlueSocket framework to create a client application that can communicate with the echo server from the previous post.

The echo client will first connect to the server to make sure it is running and then ask the user for input. When the user inputs a line of text and presses enter, the text will be sent to the server which should “echo” that text back to the client.

Whatever system you will be developing your application for, the BlueSocket github repository has instructions on how to include it with your project. The sample project on the Mastering Swift github repository uses Swift’s Package Manager to include the framework. The project, in the github repository is titled echoClient.

We will start by creating an EchoClient class and importing the frameworks that we need.

#if os(Linux)
    import Glibc
#else
    import Darwin
#endif
import Socket
import Foundation

class EchoClient {

}

In this code we import the Glibc or Darwin frameworks depending on the system we are running on.  We then import both the Socket and Foundation frameworks.  Now we need to define a couple of properties for our class.

    let bufferSize = 1024
    let port: Int
    let server: String
    var listenSocket: Socket? = nil

In this code we define four properties.  The first is the bufferSize property that defines the maximum number of characters that we can receive from the echo server at one time.  The port and server properties will define the server and port number that the echo server is running on.  The listenSocket property is the socket that we will listen to in order to receive the response back form the server.

Now we will create an initializer and a deinitializer for the EchoClient class.
   
    init(port: Int, server: String) {
        self.port = port
        self.server = server
    }
   
    deinit {
        listenSocket?.close()
    }


The initializer requires that the code calling it to provide both the port and server that we are connecting too.  We will see how to call this initializer at the end of the post.  The deinitializer disconnects the client from the server.

Now lets create the method that will connect to the server.  We will call this method start().
 
  func start() throws {
      let socket = try Socket.create()
      listenSocket = socket
      try socket.connect(to: server, port: Int32(port))
      var dataRead = Data(capacity: bufferSize)
      var cont = true
       repeat {
          print("Enter Text:")
          if let entered = readLine(strippingNewline: true) {
            try socket.write(from: entered)
            if entered.hasPrefix("quit") {
               cont = false
            }
            let bytesRead = try socket.read(into: &dataRead)
            if bytesRead > 0 {
              if let readStr = String(data: dataRead, encoding: .utf8) {
                print("Received: '\(readStr)'")
              }       
              dataRead.count = 0
            }
          }
       } while cont
    }


This code starts off by using the create() method to create a socket and then uses the connect(to:port:) method of the socket to connect to the server.  We create a dataRead variable that will contain the text that is echoed back from the server.  The capacity of the dataRead variable is the size defined by the bufferSize constant.

We now create a repeat loop that will repeat as long as the cont variable is true.  We use the readLine(strippingNewLine:) method to read the input from the user.  Once the user enters the text we use the write(from:) method to send the text to the server.  We also check to see if the users entered “quit” and if so we set the cont variable to false to end the repeat loop after this iteration.

Next we use the read(into:) method of the socket to read the response from the server.  The read(into:) method returns the number of bytes read.  If the number is greater than zero, we convert the response to a string and print it to the console.  That is all there is to it.

We would use this class like this:
do {
  var echoClient = EchoClient(port: 3333, server: "127.0.0.1")
  try echoClient.start()
} catch let error {
  print("Error: \(error)")
}

In this code we connect to the server running on the localhost (127.0.0.1) on port 3333.

As we can see with this post and the post where we created the echo server, using IBM’s BlueSocket library makes it very easy to create client and server applications with Swift.  In the next post we will add concurrency to the echo server so it can communicate with multiple servers at the same time.


2 comments: