0

I'm creating my Swift program with sockets and I was wondering if it's neccessary to use the GCDAsyncSocket library? I'm trying to create an iOS app that sends strings to my mac os x app. I've written a socket application similar to this before in Java so I'm pretty familiar with sockets. My server side (mac os) code looks like this, I am unsure how to approach the client side (iOS side)

var bsocket: GCDAsyncSocket!

func applicationDidFinishLaunching(aNotification: NSNotification) {
    bsocket = GCDAsyncSocket(delegate: self, delegateQueue: dispatch_get_main_queue())
    var port:UInt16 = 8090
    if (!bsocket.connectToHost("localhost", onPort: port, error: nil))
    {
        println("Error")
    }
    else
    {
        println("Connecting...")
    }
}

func socket(socket : GCDAsyncSocket, didReadData data:NSData, withTag tag:UInt16)
{
    var response = NSString(data: data, encoding: NSUTF8StringEncoding)
    println("Received Response")
}

func socket(socket : GCDAsyncSocket, didConnectToHost host:String, port p:UInt16)
{
    println("Connected to \(host) on port \(p).")

    var request:String = "Welcome to the server."
    var data:NSData = request.dataUsingEncoding(NSUTF8StringEncoding)!
    bsocket.writeData(data, withTimeout: -1.0, tag: 0)
    bsocket.readDataWithTimeout(-1.0, tag: 0)
}
lemonpledge
  • 1,018
  • 2
  • 10
  • 14

3 Answers3

2

This tutorial from Ray Wenderlich.com http://www.raywenderlich.com/3932/networking-tutorial-for-ios-how-to-create-a-socket-based-iphone-app-and-server has a good description of the client side needed to connect to a basic server socket. It does not do any of the handshaking, heartbeat and framing required in the websocket protocol, so it is not compatible with websockets. Your code doesn't show any of the handshaking required by the websocket protocol, so I assume that's what you want. If you need websockets, take a look at https://github.com/daltoniam/Starscream

Here are the basics of my Swift interpretation. I ended up with a Manager and a Connection:

class Manager : NSObject {
    var conn = Connection()

    func connect() {
        let (host, port) = screen.getAddress()
        conn.connect(host, port: port)
    }

    func disconnect() {
        conn.disconnect()
    }

    func sendMessage(params:[String : AnyObject]) {
        let msg = "send_message:" + JSONStringify(params)

        let data : NSData = msg.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
        var buffer = [UInt8](count:data.length, repeatedValue:0)
        data.getBytes(&buffer)

        conn.outputStream.write(UnsafePointer<UInt8>(data.bytes), maxLength: data.length)
    }

    func JSONStringify(value: AnyObject) -> String {
        if NSJSONSerialization.isValidJSONObject(value) {
            if let data = NSJSONSerialization.dataWithJSONObject(value, options: nil, error: nil) {
               if let string = NSString(data: data, encoding: NSUTF8StringEncoding) {
                   return string
                }
             }
         }
         return ""
     }
}

class Connection : NSObject, NSStreamDelegate {
var serverAddress: CFString = "127.0.0.1"
var serverPort: UInt32 = 8443

private var inputStream: NSInputStream!
private var outputStream: NSOutputStream!

func connect(address: CFString, port:UInt32) {
    println("connecting...")

    var readStream:  Unmanaged<CFReadStream>?
    var writeStream: Unmanaged<CFWriteStream>?

    CFStreamCreatePairWithSocketToHost(nil, address, port, &readStream, &writeStream)

    // Documentation suggests readStream and writeStream can be assumed to
    // be non-nil. It might be wise to test if either is nil
    // and implement error-handling as needed.

    self.inputStream = readStream!.takeRetainedValue()
    self.outputStream = writeStream!.takeRetainedValue()

    self.inputStream.delegate = self
    self.outputStream.delegate = self

    self.inputStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
    self.outputStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)

    self.inputStream.open()
    self.outputStream.open()
}

func disconnect() {
    self.inputStream.close()
    self.outputStream.close()
}


func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
    switch (eventCode){
        case NSStreamEvent.ErrorOccurred:
            NSLog("ErrorOccurred")
        case NSStreamEvent.EndEncountered:
            NSLog("EndEncountered")
        case NSStreamEvent.None:
            NSLog("None")
        case NSStreamEvent.HasBytesAvailable:
            NSLog("HasBytesAvaible")
            var buffer = [UInt8](count: 4096, repeatedValue: 0)
            while (inputStream.hasBytesAvailable){
                var len = inputStream.read(&buffer, maxLength: buffer.count)
                if(len > 0){
                    var output = NSString(bytes: &buffer, length: buffer.count, encoding: NSUTF8StringEncoding)
                    if (output != ""){
                        NSLog("server said: %@", output!)
                    }
                } else {
                    println("empty string from stream")
                }
            }
        case NSStreamEvent.allZeros:
            NSLog("allZeros")
        case NSStreamEvent.OpenCompleted:
            NSLog("OpenCompleted")
        case NSStreamEvent.HasSpaceAvailable:
            NSLog("HasSpaceAvailable")
        default: println("default reached. unknown stream event")
        }
    }
}

You might also find these links useful for messaging in Swift:

I'm not sure the JSON conversion in this code is working correctly. I discovered that I needed websockets, so this is no longer used.

Community
  • 1
  • 1
Suz
  • 3,744
  • 3
  • 23
  • 26
0

Assuming when you say "socket" you mean "web socket", I would consider using Socket Rocket, by Square. It really does a nice job and abstracting away the difficult parts of working with web sockets.

https://github.com/square/SocketRocket

InkGolem
  • 2,662
  • 1
  • 15
  • 22
0

You could use NSStream, if the iOS device is only a client and not a server.

Jeremy Pope
  • 3,342
  • 1
  • 16
  • 17
  • iOS will only be a client, I would only need it to send a "string" to the server, and send back a confirmation that it received it. Will that work with NSStream? I'll go search it up more on google right now. – lemonpledge Feb 12 '15 at 04:57