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
Related
I am using NSNetServiceBrowser and is able to find service list published by AVAHI in "didFindService" which looks like :
Service appeared: local. _https._tcp. TEMP-Mobileyes5-1C497B9ED382 -1
Service appeared: local. _https._tcp. TEMP-Mobileyes5-1C497B8E3916 -1
Service appeared: local. _https._tcp. TEMP-Mobileyes5-1C497B9ED380 -1
But not able to find IP Address and Port number of same service. I have found that code is not reaching in "netServiceDidResolveAddress" My Code is :
class ServiceDiscovery : NSObject, NSNetServiceBrowserDelegate,NSNetServiceDelegate {
var _browser:NSNetServiceBrowser!
var _service: NSNetService!
var services = [NSNetService]()
override init() {
_browser = NSNetServiceBrowser()
super.init()
_browser.delegate = self
_browser.includesPeerToPeer = true
_browser.searchForServicesOfType("_https._tcp.", inDomain: "local.")
_browser.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
}
func netServiceBrowser(browser: NSNetServiceBrowser, didFindDomain domainString: String, moreComing: Bool) {
print(domainString)
}
func netServiceBrowser(aNetServiceBrowser: NSNetServiceBrowser, didFindService aNetService: NSNetService, moreComing: Bool) {
print("Service appeared: \(aNetService)")
services.append(aNetService)
aNetService.delegate = self
aNetService.resolveWithTimeout(5.0)
}
func netServiceBrowser(browser: NSNetServiceBrowser, didNotSearch errorDict: [String : NSNumber]) {
print(errorDict)
}
func netServiceBrowser(browser: NSNetServiceBrowser, didRemoveService service: NSNetService, moreComing: Bool) {
print("Service removed: \(service)")
}
func netService(sender: NSNetService, didNotResolve errorDict: [String : NSNumber]) {
print(errorDict)
}
func netServiceDidResolveAddress(sender: NSNetService) {
print(sender.addresses![0])
}
}
The possible reason for your problem could be that you are calling the
aNetService.resolveWithTimeout(5.0)
inside another function, so as soon as
didFindService
finishes, the local variable aNetService gets destroyed (as it is a local variable for didFindService function)
SOLUTION
I see that you've already defined a variable at the top with class-wide scope named "_service"
Hence, use that by using
_service = aNetService
_service.resolveWithTimeout(5.0)
inside your didFindService
this should solve your problem. And, netServiceDidResolveAddress should get called now.
import Foundation
class ServiceDiscovery : NSObject, NetServiceBrowserDelegate,NetServiceDelegate {
var _browser:NetServiceBrowser!
var _service: NetService!
var services = [NetService]()
func searchServices(){
self.services.removeAll()
_browser = NetServiceBrowser()
_browser.delegate = self
_browser.includesPeerToPeer = true
_browser.searchForServices(ofType: "_https._tcp.", inDomain: "local.")
_browser.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
}
func updateInterface () {
for service in self.services {
if service.port == -1 {
print("service \(service.name) of type \(service.type)" +
" not yet resolved")
service.delegate = self
service.resolve(withTimeout: 0.0)
} else {
let deviceLanController = DeviceLanController()
let dict = NetService.dictionary(fromTXTRecord: service.txtRecordData()!)
let id = self.copyStringFromTXTDict(dict as [AnyHashable: Any]?, which: "id")
var ipAdd = ""
if let address = service.addresses{
if let addressOfFirstDevice = address.first{
let theAddress = addressOfFirstDevice as Data
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if getnameinfo((theAddress as NSData).bytes.bindMemory(to: sockaddr.self, capacity: theAddress.count), socklen_t(theAddress.count),
&hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 {
if let numAddress = String(validatingUTF8: hostname) {
ipAdd = numAddress
}
}
if let serviceId = id{
deviceLanController.setDeviceAvailable(serviceId, host: ipAdd, port: "\(service.port)")
}
}
}
}
}
}
fileprivate func copyStringFromTXTDict(_ dict: [AnyHashable: Any]?, which: String) -> String? {
// Helper for getting information from the TXT data
var resultString: String? = nil
if let data = dict?[which as NSObject] as! Data? {
resultString = String(data: data, encoding: String.Encoding.utf8)!
}
return resultString
}
func netServiceBrowser(_ browser: NetServiceBrowser, didFindDomain domainString: String, moreComing: Bool) {
print("didFindDomain")
print(domainString)
}
func netServiceBrowser(_ aNetServiceBrowser: NetServiceBrowser, didFind aNetService: NetService, moreComing: Bool) {
print("didFindService")
self.services.append(aNetService)
if !moreComing {
aNetService.stop()
self.updateInterface()
}
}
func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool){
print("didRemoveService")
if let ix = self.services.index(of: service) {
self.services.remove(at: ix)
print("removing a service")
if !moreComing {
self.updateInterface()
}
}
}
func netServiceBrowser(_ browser: NetServiceBrowser, didNotSearch errorDict: [String : NSNumber]) {
print("didNotSearch")
print(errorDict)
}
func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber]) {
print("didNotResolve",sender)
print(errorDict)
}
func netServiceWillResolve(_ sender: NetService) {
print("netServiceWillResolve",sender)
}
func netServiceDidResolveAddress(_ sender: NetService) {
print("netServiceDidResolveAddress",sender)
self.updateInterface()
}
}
This answer solved my problem. I am resolving and saving each address in my coredata so i can use that address for connecting local services.
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.
}
}
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
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)
}
}
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.