TCP socket connection using CFStreamCreatePairWithSocketToHost not Working - ios

I am new to swift Programming. I am trying to connect to a server socket from my ios app. I have a View controller and in a button action I am calling the function to connect to the socket server
let socketConn = Connection();
socketConn.connect();
I have set the delegate to self in the Connection class, but my stream function is not triggered after connecting to the server socket.
class Connection : NSObject, NSStreamDelegate {
let serverAddress: CFString = "192.168.1.104"
let serverPort: UInt32 = 5012
private var inputStream: NSInputStream!
private var outputStream: NSOutputStream!
func connect() {
println("connecting...")
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
CFStreamCreatePairWithSocketToHost(nil, self.serverAddress, self.serverPort, &readStream, &writeStream)
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 stream(stream: NSStream, handleEvent eventCode: NSStreamEvent) {
println("stream event")
}
}
Can anyone help me how to debug it on why the stream function is called on connection ?

I am using getStreamsToHostWithName function of NSStream class. It is more easy and beeter than CFStreamCreatePairWithSocketToHost
func initNetworkCommunication() {
print("connecting...")
let serverAddress = "gzoa.vps.infomaniak.com"
let serverPort = 1234
NSStream.getStreamsToHostWithName(serverAddress, port: serverPort, inputStream: &inputStream, outputStream: &outputStream)
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()
}

You can use this
import Foundation
typealias OnComing = (String!) -> (Void)
class SocketClient: NSObject, StreamDelegate {
var host:String?
var port:Int?
var inputStream: InputStream?
var outputStream: OutputStream?
var status = false;
var output = ""
var bufferSize = 1024;
var onComing:OnComing!
func makeCFStreamConnection(host: String, port: Int, onComing:#escaping OnComing) {
self.host = host
self.port = port
self.onComing = onComing
Stream.getStreamsToHost(withName: host, port: port, inputStream: &self.inputStream, outputStream: &self.outputStream)
if self.inputStream != nil && self.outputStream != nil {
self.inputStream!.delegate = self
self.outputStream!.delegate = self
self.inputStream!.schedule(in: .main, forMode: RunLoopMode.defaultRunLoopMode)
self.outputStream!.schedule(in: .main, forMode: RunLoopMode.defaultRunLoopMode)
self.inputStream!.open()
self.outputStream!.open()
}
}
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
if aStream === self.inputStream {
switch eventCode {
case Stream.Event.errorOccurred:
break
case Stream.Event.openCompleted:
break
case Stream.Event.hasBytesAvailable:
read()
break
default:
break
}
} else if aStream === self.outputStream {
switch eventCode {
case Stream.Event.errorOccurred:
break
case Stream.Event.openCompleted:
break
case Stream.Event.hasSpaceAvailable:
break
default:
break
}
}
}
func read() {
output = ""
var buffer = [UInt8](repeating: 0, count: bufferSize)
while (self.inputStream!.hasBytesAvailable) {
let bytesRead: Int = inputStream!.read(&buffer, maxLength: buffer.count)
if bytesRead >= 0 {
output += NSString(bytes: UnsafePointer(buffer), length: bytesRead, encoding: String.Encoding.ascii.rawValue)! as String
} else {
print("# Stream read() error")
}
}
self.onComing(output)
}
func write(message:String) {
let encodedDataArray = [UInt8]("\(message)\n".utf8)
self.outputStream?.write(encodedDataArray, maxLength: encodedDataArray.count)
}
}

Related

get file in InputStream from socket Swift IOS

i Want to get file in Input Stream From Socket In swift
There are many examples to get a string from the socket but did not find any method to get a socket file
// To connect to the server
func connect(host: String, port: Int) {
SwifterHandler.sharedInstance.FilePathSave = SwifterHandler.sharedInstance.rootDoc()
self.host = host
self.port = port
Stream.getStreamsToHost(withName: host, port: port, inputStream: &self.inputStream, outputStream: &self.outputStream)
if self.inputStream != nil && self.outputStream != nil {
self.inputStream!.delegate = self
self.outputStream!.delegate = self
self.inputStream!.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
self.outputStream!.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
self.inputStream!.open()
self.outputStream!.open()
}
}
// This is a call back func that takes care of I/O from/to the server.
// Read about this func. There are many event codes to handle.
// I just wanted to make it simple.
func stream(aStream: Stream, handleEvent eventCode: Stream.Event) {
print("Event : \(eventCode)")
if aStream != inputStream {
return
}
if eventCode == .hasBytesAvailable {
self.ReadFile()
}
}
private func ReadFile()
{
var buffer = [UInt8](repeating: 0, count: 1024)
if let fh = FileHandle(forWritingAtPath: "\(SwifterHandler.sharedInstance.FilePathSave)/test.png") {
fh.seekToEndOfFile()
while (self.inputStream!.hasBytesAvailable){
let bytesRead: Int = inputStream!.read(&buffer, maxLength: buffer.count)
if bytesRead >= 0 {
fh.write(Data(bytes: buffer))
}
}
fh.closeFile()
}
SwifterHandler.sharedInstance.SharedFile(path: SwifterHandler.sharedInstance.FilePathSave)
self.dataReadCallback!("Success Download")
InstallApp().InstallApplication()
self.dataReadCallback!("Application Installed")
}
ReadFile() do not run when server send file
class ViewController: UIViewController,StreamDelegate
{
var inputstream: InputStream?
var outputstream: OutputStream?
var host: String?
var port: Int?
override func viewDidLoad()
{
super.viewDidLoad()
let _ = initNetworkCommunication()
let word = "Hello are you there->"
let buf = [UInt8](word.utf8)
print("This is buf = \(buf))")
outputstream?.write(buf, maxLength: buf.count)
}
func initNetworkCommunication()
{
host = "127.0.0.1" //this is IP number passing as string
port = 34 //this is port number
Stream.getStreamsToHost(withName: host!, port: port!,inputStream: &inputstream, outputStream: &outputstream)
//here we are going to calling a delegate function
inputstream?.delegate = self as? StreamDelegate
outputstream?.delegate = self as? StreamDelegate
inputstream?.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
outputstream?.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
inputstream?.open()
print("Here the input stream will open")
outputstream?.open()
print("connected")
}
func stream(_ aStream: Stream, handle eventCode: Stream.Event)
{
print("we are in delegate method")
print("EventCode = \(eventCode)")
switch (eventCode)
{
case Stream.Event.openCompleted:
if(aStream == outputstream)
{
print("output:OutPutStream opened")
}
print("Input = openCompleted")
break
case Stream.Event.errorOccurred:
if(aStream === outputstream)
{
print("output:Error Occurred\n")
}
print("Input : Error Occurred\n")
break
case Stream.Event.endEncountered:
if(aStream === outputstream)
{
print("output:endEncountered\n")
}
print("Input = endEncountered\n")
break
case Stream.Event.hasSpaceAvailable:
if(aStream === outputstream)
{
print("output:hasSpaceAvailable\n")
}
print("Input = hasSpaceAvailable\n")
break
case Stream.Event.hasBytesAvailable:
if(aStream === outputstream)
{
print("output:hasBytesAvailable\n")
}
if aStream === inputstream
{
print("Input:hasBytesAvailable\n")
var buffer = [UInt8](repeating: 0, count: 4096)
//print("input buffer = \(buffer)")
// sleep(40)
while (self.inputstream!.hasBytesAvailable)
{
let len = inputstream!.read(&buffer, maxLength: buffer.count)
// If read bytes are less than 0 -> error
if len < 0
{
let error = self.inputstream!.streamError
print("Input stream has less than 0 bytes\(error!)")
//closeNetworkCommunication()
}
// If read bytes equal 0 -> close connection
else if len == 0
{
print("Input stream has 0 bytes")
// closeNetworkCommunication()
}
if(len > 0)
//here it will check it out for the data sending from the server if it is greater than 0 means if there is a data means it will write
{
let messageFromServer = NSString(bytes: &buffer, length: buffer.count, encoding: String.Encoding.utf8.rawValue)
if messageFromServer == nil
{
print("Network hasbeen closed")
// v1.closeNetworkCommunication()
}
else
{
print("MessageFromServer = \(String(describing: messageFromServer))")
}
}
}
}
break
default:
print("default block")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Swift 3 stream delegate even handler error

I am writing a very, very simple TCP socket app that sends and receives data from a server; my app uses delegates; most of the code I found from online but none of the event handlers for the streams are working; any ideas on why the following method is never being called?
UPDATE: this question has been answered here:
Non-responsive stream delegate in Swift
However, the problem that I am facing is how do I flush the output stream after the buffer is full? I would like send data in real time to my server, but I am getting a "broken pipe" from stream output error
/**
NSStream Delegate Method where we handle errors, read and write data from input and output streams
:param: stream NStream that called delegate method
:param: eventCode Event Code
*/
final func stream(stream: Stream, handleEvent eventCode: Stream.Event) {
switch eventCode {
case Stream.Event.endEncountered:
endEncountered(stream: stream)
case Stream.Event.errorOccurred:
print("[SCKT]: ErrorOccurred: \(stream.streamError?.localizedDescription)")
case Stream.Event.openCompleted:
print("open completed")
openCompleted(stream: stream)
case Stream.Event.hasBytesAvailable:
handleIncommingStream(stream: stream)
case Stream.Event.hasSpaceAvailable:
print("space available")
writeToStream()
default:
print("default!")
}
}
UIViewController
import Darwin
import Foundation
import UIKit
import Dispatch
class ViewController: UIViewController {
#IBOutlet private weak var joystickMove: Joystick!
#IBOutlet private weak var joystickRotate: Joystick!
private var joystick = Joystick()
private var contour = Contours()
private var contour_index: Int = 0
private var ip_address = "000.000.00.0" as CFString
private var port: Int = 0000
private var control_socket: Socket
// private var control_socket: Socket = Socket()
private var toast_label: UILabel = UILabel()
// let dataProcessingQueue = DispatchQueue.main
// convenience init() {
// self.control_socket = Socket()
// }
// init(coder aDecoder: NSCoder!) {
// super.init(coder: aDecoder)
// }
// init(imageURL: NSURL?) {
// self.control_socket = Socket()
// self.control_socket.open(host: self.ip_address as String!, port: self.port)
// super.init(nibName: nil, bundle: nil)
// }
// required init?(coder aDecoder: NSCoder) {
// fatalError("init(coder:) has not been implemented")
// }
required init(coder aDecoder: NSCoder) {
print("here!")
self.control_socket = Socket()
// self.control_socket.open(host: self.ip_address as String!, port: self.port)
print("here(2)!")
super.init(coder: aDecoder)!
}
override func viewDidLoad() {
super.viewDidLoad()
self.control_socket.open(host: self.ip_address as String!, port: self.port)
createJoystick()
createContours()
createViewsButton()
recvLidarData()
}
private func requestIsComplete() -> Bool {
// This function should find out if all expected data was received and return 'true' if it did.
return true
}
private func processData(data: Data) {
// This function should do something with the received data
}
private func recvLidarData() {
let concurrentQueue = DispatchQueue(label: "queuename", attributes: .concurrent)
concurrentQueue.async {
// recieve the data here!
}
}
private func createToast() {
self.toast_label = UILabel(frame: CGRect(x: self.view.frame.size.width/2 - 150, y: self.view.frame.size.height-100, width: 300, height: 35))
self.toast_label.backgroundColor = UIColor.black
self.toast_label.textColor = UIColor.white
self.toast_label.textAlignment = NSTextAlignment.center;
self.view.addSubview(self.toast_label)
self.toast_label.text = "Could not connect to server"
self.toast_label.alpha = 1.0
self.toast_label.layer.cornerRadius = 10;
self.toast_label.clipsToBounds = true
UIView.animate(withDuration: 4.0, delay: 0.1, options: UIViewAnimationOptions.curveEaseOut, animations: {
self.toast_label.alpha = 0.0
})
}
private func createJoystick() {
let n: CGFloat = 100.0
let x: CGFloat = (UIScreen.main.bounds.width/2) - (n/2.0)
let y: CGFloat = UIScreen.main.bounds.height - (UIScreen.main.bounds.height/4.0)
self.joystick.frame = CGRect(x: x, y: y, width: n, height: n)
self.joystick.backgroundColor = UIColor.clear
self.joystick.substrateColor = UIColor.lightGray
self.joystick.substrateBorderColor = UIColor.gray
self.joystick.substrateBorderWidth = 1.0
self.joystick.stickSize = CGSize(width: 50.0, height: 50.0)
self.joystick.stickColor = UIColor.darkGray
self.joystick.stickBorderColor = UIColor.black
self.joystick.stickBorderWidth = 2.0
self.joystick.fade = 0.5
self.joystick.ip_address = self.ip_address
self.joystick.port = self.port
var packet = ""
DispatchQueue.global(qos: .userInitiated).async { // do some task
// self.control_socket = Socket()
// self.control_socket.open(host: self.ip_address as String!, port: self.port)
self.joystick.trackingHandler = { (data) -> () in
var power = sqrt(pow(Double(data.velocity.x), 2.0) + pow(Double(data.velocity.y), 2.0))
let theta = atan2(Double(-data.velocity.y), Double(data.velocity.x))
let degrees = theta * (180.0 / M_PI)
power = power/1.2
if degrees >= 55 && degrees <= 125 { // move forward
packet = "\(1) \(1) \(power) \(power)"
} else if degrees >= -125 && degrees <= -55 { // move backwards
packet = "\(-1) \(-1) \(power) \(power)"
} else if degrees >= -55 && degrees <= 55 { // turn right
packet = "\(1) \(-1) \(power) \(power)"
} else { // turn left
packet = "\(-1) \(1) \(power) \(power)"
}
}
print("packet: \(packet)")
self.control_socket.send(message: packet)
print("sent")
}
view.addSubview(joystick)
}
private func createContours() {
let n: CGFloat = 350.0
let x: CGFloat = (UIScreen.main.bounds.width/2.0) - (n/2.0)
let y: CGFloat = UIScreen.main.bounds.height - (UIScreen.main.bounds.height/4.0) - n - 100.0
self.contour.frame = CGRect(x: x, y: y, width: n, height: n)
self.contour.backgroundColor = UIColor.clear
view.addSubview(self.contour)
}
private func createViewsButton() {
let width: CGFloat = 150.0
let height: CGFloat = 75.0
let x: CGFloat = (UIScreen.main.bounds.width/2.0) - (width/2.0)
let y: CGFloat = UIScreen.main.bounds.height - (UIScreen.main.bounds.height/4.0) - width
let button: UIButton = UIButton(frame: CGRect(x: x, y: y, width: width, height: height))
button.backgroundColor = UIColor.blue
button.setTitle("Contour Views", for: .normal)
button.addTarget(self, action: #selector(self.buttonAction), for: .touchUpInside)
button.tag = 1
view.addSubview(button)
}
#objc private func buttonAction(sender: UIButton!) {
var btnsendtag: UIButton = sender
if btnsendtag.tag == 1 {
self.contour_index = (self.contour_index + 1) % 2
switch self.contour_index {
case 0:
for index in 0...356 {
if self.contour.distx[index] != -1 && self.contour.disty[index] != -1 {
self.contour.circles[index].alpha = 0
}
}
case 1:
for index in 0...356 {
if self.contour.distx[index] != -1 && self.contour.disty[index] != -1 {
self.contour.circles[index].alpha = 1
}
}
default:
for index in 0...356 {
if self.contour.distx[index] != -1 && self.contour.disty[index] != -1 {
self.contour.circles[index].alpha = 1
UIColor.cyan.setFill()
self.contour.lines[index].fill()
self.contour.lines[index].stroke()
}
}
}
}
}
override func viewDidAppear(_ animated: Bool) {
}
public func delayWithSeconds(_ seconds: Double, completion: #escaping () -> ()) {
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
completion()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillDisappear(_ animated: Bool) {
}
}
Socket class
import UIKit
import Foundation
#objc protocol SocketStreamDelegate{
func socketDidConnect(stream:Stream)
#objc optional func socketDidDisconnet(stream:Stream, message:String)
#objc optional func socketDidReceiveMessage(stream:Stream, message:String)
#objc optional func socketDidEndConnection()
}
class Socket: NSObject, StreamDelegate {
var delegate:SocketStreamDelegate?
private let bufferSize = 1024
private var _host:String?
private var _port:Int?
private var _messagesQueue:Array<String> = [String]()
private var _streamHasSpace:Bool = false
private var inputStream: InputStream?
private var outputStream: OutputStream?
var isClosed = false
var isOpen = false
var host:String?{
get{
return self._host
}
}
var port:Int?{
get{
return self._port
}
}
deinit{
if let inputStr = self.inputStream{
inputStr.close()
inputStr.remove(from: .main, forMode: RunLoopMode.defaultRunLoopMode)
}
if let outputStr = self.outputStream{
outputStr.close()
outputStr.remove(from: .main, forMode: RunLoopMode.defaultRunLoopMode)
}
}
/**
Opens streaming for both reading and writing, error will be thrown if you try to send a message and streaming hasn't been opened
:param: host String with host portion
:param: port Port
*/
final func open(host:String!, port:Int!){
self._host = host
self._port = port
var inStreamUnmanaged:Unmanaged<CFReadStream>?
var outStreamUnmanaged:Unmanaged<CFWriteStream>?
CFStreamCreatePairWithSocketToHost(nil, host as CFString!, UInt32(port), &inStreamUnmanaged, &outStreamUnmanaged)
inputStream = inStreamUnmanaged?.takeRetainedValue()
outputStream = outStreamUnmanaged?.takeRetainedValue()
if inputStream != nil && outputStream != nil {
inputStream!.delegate = self
outputStream!.delegate = self
// var myloop = RunLoop.current
// inputStream!.schedule(in: myloop, forMode: RunLoopMode.defaultRunLoopMode)
// outputStream!.schedule(in: myloop, forMode: RunLoopMode.defaultRunLoopMode)
inputStream!.schedule(in: .main, forMode: RunLoopMode.defaultRunLoopMode)
outputStream!.schedule(in: .main, forMode: RunLoopMode.defaultRunLoopMode)
print("[SCKT]: Open Stream")
self._messagesQueue = Array()
inputStream!.open()
outputStream!.open()
// myloop.run()
print("Run")
} else {
print("[SCKT]: Failed Getting Streams")
}
}
final func close(){
if let inputStr = self.inputStream {
inputStr.delegate = nil
inputStr.close()
inputStr.remove(from: .main, forMode: RunLoopMode.defaultRunLoopMode)
}
if let outputStr = self.outputStream {
outputStr.delegate = nil
outputStr.close()
outputStr.remove(from: .main, forMode: RunLoopMode.defaultRunLoopMode)
}
isClosed = true
}
/**
NSStream Delegate Method where we handle errors, read and write data from input and output streams
:param: stream NStream that called delegate method
:param: eventCode Event Code
*/
final func stream(stream: Stream, handleEvent eventCode: Stream.Event) {
switch eventCode {
case Stream.Event.endEncountered:
endEncountered(stream: stream)
case Stream.Event.errorOccurred:
print("[SCKT]: ErrorOccurred: \(stream.streamError?.localizedDescription)")
case Stream.Event.openCompleted:
print("open completed")
openCompleted(stream: stream)
case Stream.Event.hasBytesAvailable:
handleIncommingStream(stream: stream)
case Stream.Event.hasSpaceAvailable:
print("space available")
writeToStream()
default:
print("default!")
}
}
final func endEncountered(stream: Stream) {
}
final func openCompleted(stream: Stream){
if(self.inputStream!.streamStatus == .open && self.outputStream!.streamStatus == .open) {
let justAOneTimeThing: () = {
self.isOpen = true
self.delegate!.socketDidConnect(stream: stream)
}()
}
}
/**
Reads bytes asynchronously from incomming stream and calls delegate method socketDidReceiveMessage
:param: stream An NSInputStream
*/
final func handleIncommingStream(stream: Stream) {
if stream is InputStream {
var buffer = [UInt8](repeating: 0, count: bufferSize)
DispatchQueue.global(qos: .userInitiated).async {
let len = self.inputStream?.read(&buffer, maxLength: buffer.count)
if len! >= 0 {
if let output = NSString(bytes: &buffer, length: len!, encoding: String.Encoding.utf8.rawValue) {
self.delegate?.socketDidReceiveMessage!(stream: stream, message: output as String)
}
} else {
// Handle error
}
}
} else {
print("[SCKT]: \(#function) : Incorrect stream received")
}
}
/**
If messages exist in _messagesQueue it will remove and it and send it, if there is an error
it will return the message to the queue
*/
final func writeToStream() {
if _messagesQueue.count > 0 && self.outputStream!.hasSpaceAvailable {
DispatchQueue.global(qos: .userInitiated).async {
let message = self._messagesQueue.removeLast()
let buff = [UInt8](message.utf8)
if self.outputStream!.write(buff, maxLength: buff.count) == -1 {
self._messagesQueue.append(message)
}
}
}
}
final func send(message:String){
_messagesQueue.insert(message, at: 0)
writeToStream()
}
}
Maybe your stream function prototype is incorrect. Your prototype is
final func stream(stream: Stream, handleEvent eventCode: Stream.Event)
Try this:
func stream(_ aStream: Stream, handle eventCode: Stream.Event)
in your Socket class

swift - How to give and parse data from swift?

I'm a socket project in swift. I try to give data that are JSON and Parse them but i have two problem:
1- when I received data are incomplete and return nil value for some bytes.
2- I don't know when The receiving data ends. I receive data in NSSTreamEvent.hasBytesAvailable but never run the NSStreamEvent.EndEncountered and after some moments the code was error and app crashed.
3- My socket 2 times open while I call them 1 time...
There is my code :
import Foundation
class SocketManager : NSObject , NSStreamDelegate {
let ip = "192.168.1.12"
let port = 6969
let introduceStr = ["Type" : 4 , "MobileID" : 2 , "Introduce" : ["ExKey" : 123]]
let jsonParser = JsonMaker() // This is a class for convert string to json
var inputStream : NSInputStream?
var outputStream : NSOutputStream?
var openedSocket = Int()
var total = NSString()
override init() {
openedSocket = 0
}
func openSocket() {
NSStream.getStreamsToHostWithName(ip, port: port, inputStream: &inputStream, outputStream: &outputStream)
let inputStatus : NSStreamStatus = (inputStream?.streamStatus)!
let outputStatus : NSStreamStatus = (outputStream?.streamStatus)!
if inputStatus != NSStreamStatus.Reading && inputStatus != NSStreamStatus.Open && inputStatus != NSStreamStatus.Opening && outputStatus != NSStreamStatus.Writing && outputStatus != NSStreamStatus.Open && outputStatus != NSStreamStatus.Opening {
inputStream?.delegate = self
outputStream?.delegate = self
inputStream?.scheduleInRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
outputStream?.scheduleInRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
inputStream?.open()
outputStream?.open()
}
}
func tryOpen() {
inputStream?.close()
outputStream?.close()
inputStream?.removeFromRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
outputStream?.removeFromRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
performSelector("openSocket", withObject: nil, afterDelay: 5)
}
func closeSocket() {
inputStream?.removeFromRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
outputStream?.removeFromRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
inputStream?.close()
outputStream?.close()
performSelector("openSocket", withObject: nil, afterDelay: 15)
}
func getData(aStream : NSStream) {
if (aStream == inputStream) {
let MAXSIZE = 1024 * 8
var allLength = Int()
var buffer = [UInt8](count: MAXSIZE , repeatedValue: 0)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
while self.inputStream?.hasBytesAvailable == true {
let readBytes = self.inputStream?.read(&buffer, maxLength: sizeofValue(buffer))
allLength += readBytes!
if readBytes > 0 {
let data : NSData = NSData(bytes: &buffer, length: sizeofValue(buffer))
if let str = NSString(data: data, encoding: NSUTF8StringEncoding) {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.total = (self.total as String) + (str as String)
})
}
}
}
})
}
}
func sendData(message : NSString ) -> Int{
if openedSocket == 0 {
return -1
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
let data : NSData = message.dataUsingEncoding(NSUTF8StringEncoding)!
var buffer = [UInt8](count: (data.length), repeatedValue: 0)
data.getBytes(&buffer, length: buffer.count)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.outputStream!.write(&buffer, maxLength: (data.length))
})
})
return 1
}
}
func introduce() {
if openedSocket == 1{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
let str = self.jsonParser.dictionaryToJson(self.introduceStr)
let data : NSData = str.dataUsingEncoding(NSUTF8StringEncoding)!
var buffer = [UInt8](count: (data.length), repeatedValue: 0)
data.getBytes(&buffer, length: buffer.count)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.outputStream!.write(&buffer, maxLength: (data.length))
print("the output introducing is finised")
})
})
} else {
tryOpen()
}
}
func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
switch eventCode {
case NSStreamEvent.ErrorOccurred :
print("This is the Errorrr")
break
case NSStreamEvent.OpenCompleted :
openedSocket = 1
performSelector("introduce", withObject: nil, afterDelay: 0.3)
break
case NSStreamEvent.HasBytesAvailable :
getData(aStream)
break
case NSStreamEvent.EndEncountered :
print(total)
break
default :
break
}
}
}

Swift: NSStreamDelegate not receiving NSStreamEvent.HasBytesAvailable after send

I'm trying to open a socket in swift that talks to an imap server. After sending a command through the socket I'm not seeing a NSStreamEvent.HasBytesAvailable event on the inputStream.
Here's the log output from my code:
# connecting to imap.gmail.com:993
NSStreamEvent.OpenCompleted <__NSCFInputStream: 0x7fdf80543590>
NSStreamEvent.OpenCompleted <__NSCFOutputStream: 0x7fdf80540e30>
NSStreamEvent.HasBytesAvailable <__NSCFInputStream: 0x7fdf80543590>
NSStreamEvent.HasSpaceAvailable <__NSCFOutputStream: 0x7fdf80540e30>
< * OK Gimap ready for requests from 50.156.116.68 ra6mb82064609pab
> ABC1 CAPABILITY
NSStreamEvent.HasSpaceAvailable <__NSCFOutputStream: 0x7fdf80540e30>
My code
I have a simple storyboard with connect, read and send buttons
ViewController.swift
import UIKit
class ViewController: UIViewController {
var socketConnection :SocketConnection!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func connect() {
socketConnection = SocketConnection(host: "imap.gmail.com", port: 993, useSSL: true)
socketConnection.connect()
}
#IBAction func read() {
socketConnection.read()
}
#IBAction func send() {
socketConnection.send("ABC1 CAPABILITY\n")
}
}
Socketconnection.swift
import Foundation
class SocketConnection: NSObject, NSStreamDelegate {
let host :String
let port :UInt32
let useSSL :Bool
let bufferSize = 4096
let encoding : UInt = NSUTF8StringEncoding
var inputStream : NSInputStream?
var outputStream : NSOutputStream?
init(host: String, port:UInt32, useSSL:Bool){
self.host = host
self.port = port
self.useSSL = useSSL
super.init()
}
func stream(aStream: NSStream, handleEvent aStreamEvent: NSStreamEvent) {
switch aStreamEvent {
case NSStreamEvent.OpenCompleted:
println("NSStreamEvent.OpenCompleted \(aStream.description)")
case NSStreamEvent.HasBytesAvailable:
println("NSStreamEvent.HasBytesAvailable \(aStream.description)")
case NSStreamEvent.HasSpaceAvailable:
println("NSStreamEvent.HasSpaceAvailable \(aStream.description)")
case NSStreamEvent.EndEncountered:
println("NSStreamEvent.EndEncountered \(aStream.description)")
case NSStreamEvent.None:
println("NSStreamEvent.None \(aStream.description)")
case NSStreamEvent.ErrorOccurred:
println("NSStreamEvent.ErrorOccurred \(aStream.description)")
default:
println("# something weird happend")
}
}
func connect() {
println("# connecting to \(host):\(port)")
var cfReadStream : Unmanaged<CFReadStream>?
var cfWriteStream : Unmanaged<CFWriteStream>?
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, &cfReadStream, &cfWriteStream)
inputStream = cfReadStream!.takeUnretainedValue()
outputStream = cfWriteStream!.takeUnretainedValue()
if self.useSSL {
inputStream!.setProperty(kCFStreamSocketSecurityLevelNegotiatedSSL, forKey: kCFStreamPropertySocketSecurityLevel)
outputStream!.setProperty(kCFStreamSocketSecurityLevelNegotiatedSSL, forKey: kCFStreamPropertySocketSecurityLevel)
}
inputStream!.delegate = self
outputStream!.delegate = self
inputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
outputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
inputStream!.open()
outputStream!.open()
}
func read(){
var buffer = [UInt8](count: bufferSize, repeatedValue: 0)
var output: String = ""
while (self.inputStream!.hasBytesAvailable){
var bytesRead: Int = inputStream!.read(&buffer, maxLength: buffer.count)
if bytesRead >= 0 {
output += NSString(bytes: UnsafePointer(buffer), length: bytesRead, encoding: encoding)!
} else {
println("# error")
}
println("< \(output)")
}
}
func send(message:String){
if (self.outputStream!.hasSpaceAvailable){
let data:NSData = message.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
let bytesWritten = self.outputStream!.write(UnsafePointer(data.bytes), maxLength: data.length)
println("> \(message)")
} else {
println("# steam busy")
}
}
}
The same command works using openssl s_client
openssl s_client -connect imap.gmail.com:993 -crlf
... SSL HANDSHAKE ...
---
* OK Gimap ready for requests from 50.156.116.68 st4mb69201226pbc
ABC1 CAPABILITY
* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH AUTH=XOAUTH2 AUTH=PLAIN AUTH=PLAIN-CLIENTTOKEN
ABC1 OK Thats all she wrote! st4mb69201226pbc

XMPP connection issue on IOS using Swift

I am trying to use the XMPP framework(https://github.com/robbiehanson/XMPPFramework) using swift.
I am new to swift
class ViewController: UIViewController {
var password: NSString?
var isOpen: Bool = false
var xstream: XMPPStream?
var loginServer: String = ""
override func viewDidLoad() {
super.viewDidLoad()
println(connect())
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func connect() ->Bool{
var xstream = XMPPStream()
var error: NSError?
xstream.addDelegate(self, delegateQueue: dispatch_get_main_queue())
xstream.myJID = XMPPJID.jidWithString("test#localhost")
xstream.hostName="127.0.0.1"
xstream.hostPort=5222
var password = "testing"
if !xstream.connectWithTimeout(XMPPStreamTimeoutNone, error: &error) {
println(error)
}
println(xstream.isConnecting()) // This prints true
return xstream.isConnected();// This prints false.
}
}
The username and password and server details are correct because i use adium to connect to server and it works fine.
Set your host name and port.
Call methods as described below.
configureXMPP()
configureXMPPElements()
loginWithId("userId", password: "password")
After this, delegate methods will be called and authentication will be done.
After authentication, one must send presence.
self.xmppStream.send(XMPPPresence())
private var hostName: String = "your host name"
private var hostPort: UInt16 = 5222
private var xmppStream: XMPPStream!
private var xmppReconnect: XMPPReconnect!
private var xmppRoster: XMPPRoster!
private var xmppvCardStorage: XMPPvCardCoreDataStorage!
private var xmppvCardTempModule: XMPPvCardTempModule!
private var xmppvCardAvatarModule: XMPPvCardAvatarModule!
private var xmppCapabilities: XMPPCapabilities!
private var xmppCapabilitiesStorage: XMPPCapabilitiesCoreDataStorage!
private var xmppMessageArchivingStorage: XMPPMessageArchivingCoreDataStorage!
private var xmppMessageArchivingModule: XMPPMessageArchiving!
private var xmppAutoPing: XMPPAutoPing!
private var userId = ""
private var password = ""
fileprivate func configureXMPP() {
// Stream Configuration
xmppStream = XMPPStream()
xmppStream.addDelegate(self, delegateQueue: DispatchQueue.main)
xmppStream.hostPort = hostPort
xmppStream.hostName = hostName
xmppStream.enableBackgroundingOnSocket = true
xmppStream.keepAliveInterval = 0.5;
xmppStream.startTLSPolicy = .required
}
fileprivate func configureXMPPElements() {
//Autoping
xmppAutoPing = XMPPAutoPing(dispatchQueue: DispatchQueue.main)
xmppAutoPing?.activate(xmppStream)
xmppAutoPing?.addDelegate(self, delegateQueue: DispatchQueue.main)
xmppAutoPing?.pingInterval = 2
xmppAutoPing?.pingTimeout = 2
// Reconnect
self.xmppReconnect = XMPPReconnect()
// Storage
let xmppRosterStorage = XMPPRosterCoreDataStorage()
self.xmppRoster = XMPPRoster(rosterStorage: xmppRosterStorage, dispatchQueue: DispatchQueue.main)
self.xmppRoster.autoFetchRoster = true
self.xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = true
self.xmppvCardStorage = XMPPvCardCoreDataStorage.sharedInstance()
self.xmppvCardTempModule = XMPPvCardTempModule(vCardStorage: xmppvCardStorage)
self.xmppvCardAvatarModule = XMPPvCardAvatarModule(vCardTempModule: xmppvCardTempModule)
self.xmppCapabilitiesStorage = XMPPCapabilitiesCoreDataStorage.sharedInstance()
self.xmppCapabilities = XMPPCapabilities(capabilitiesStorage: xmppCapabilitiesStorage)
self.xmppMessageArchivingStorage = XMPPMessageArchivingCoreDataStorage.sharedInstance()
self.xmppMessageArchivingModule = XMPPMessageArchiving(messageArchivingStorage: xmppMessageArchivingStorage)
self.xmppMessageArchivingModule.clientSideMessageArchivingOnly = false
self.xmppMessageArchivingModule.activate(self.xmppStream)
self.xmppMessageArchivingModule.addDelegate(self, delegateQueue: DispatchQueue.main)
//Activate xmpp modules
self.xmppReconnect.activate(self.xmppStream)
self.xmppRoster.activate(self.xmppStream)
self.xmppvCardTempModule.activate(self.xmppStream)
self.xmppvCardAvatarModule.activate(self.xmppStream)
self.xmppCapabilities.activate(self.xmppStream)
// Add ourself as a delegate to anything we may be interested in
self.xmppRoster.addDelegate(self, delegateQueue: DispatchQueue.main)
}
func loginWithId(_ userId: String, password: String) {
if self.xmppStream == nil {
establishConnection()
}
self.userId = userId
self.password = password
xmppStream.myJID = XMPPJID(string: userId)
do {
try xmppStream?.connect(withTimeout: XMPPStreamTimeoutNone)
} catch {
print("connection failed")
}
}
fileprivate func authentictae() {
do {
try self.xmppStream.authenticate(withPassword: password)
}
catch {
print("not authenticate")
}
}
// Delegate Methods
func xmppStream(_ sender: XMPPStream!, socketDidConnect socket: GCDAsyncSocket!) {
print("socketDidConnect:")
sender.enableBackgroundingOnSocket = true
}
func xmppStreamDidStartNegotiation(_ sender: XMPPStream!) {
print("xmppStreamDidStartNegotiation:")
}
func xmppStreamDidConnect(_ sender: XMPPStream!) {
authentictae()
print("Stream: Connected")
}
func xmppStreamDidAuthenticate(_ sender: XMPPStream!) {
print("Stream: Authenticated")
}
Remember the connection takes some seconds to be established.
Use the other delegate methods to track the state of the connection.

Resources