BACKGROUND:
I want to be able to send and receive UDP packets between my iOS app and a server.
The server echoes back every incoming message to the client the app. The server is tested and confirmed working. I have a StartViewController which starting up two classes that implements GCDAsyncUdpSocketDelegate, one for sending and one for receiving. The "sending socket" is working, the server receives the messages.
PROBLEM:
The app never get the incoming message back after it been sent. Something with the listening socket setup is probably wrong since didReceiveData never get called.
Have I done this completely wrong?
Start:
class StartViewController: UIViewController {
var inSocket : InSocket!
var outSocket : OutSocket!
override func viewDidLoad() {
super.viewDidLoad()
inSocket = InSocket()
outSocket = OutSocket()
}
#IBAction func goButton(sender: UIButton) {
outSocket.send("This is a message!")
}
}
Receive:
class InSocket: NSObject, GCDAsyncUdpSocketDelegate {
let IP = "255.255.255.255"
let PORT:UInt16 = 5556
var socket:GCDAsyncUdpSocket!
override init(){
super.init()
setupConnection()
}
func setupConnection(){
var error : NSError?
socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: dispatch_get_main_queue())
socket.bindToPort(PORT, error: &error)
socket.enableBroadcast(true, error: &error)
socket.joinMulticastGroup(IP, error: &error)
socket.beginReceiving(&error)
}
func udpSocket(sock: GCDAsyncUdpSocket!, didReceiveData data: NSData!, fromAddress address: NSData!, withFilterContext filterContext: AnyObject!) {
println("incoming message: \(data)");
}
}
Send:
class OutSocket: NSObject, GCDAsyncUdpSocketDelegate {
let IP = "90.112.76.180"
let PORT:UInt16 = 5556
var socket:GCDAsyncUdpSocket!
override init(){
super.init()
setupConnection()
}
func setupConnection(){
var error : NSError?
socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: dispatch_get_main_queue())
socket.connectToHost(IP, onPort: PORT, error: &error)
}
func send(message:String){
let data = message.dataUsingEncoding(NSUTF8StringEncoding)
socket.sendData(data, withTimeout: 2, tag: 0)
}
func udpSocket(sock: GCDAsyncUdpSocket!, didConnectToAddress address: NSData!) {
println("didConnectToAddress");
}
func udpSocket(sock: GCDAsyncUdpSocket!, didNotConnect error: NSError!) {
println("didNotConnect \(error)")
}
func udpSocket(sock: GCDAsyncUdpSocket!, didSendDataWithTag tag: Int) {
println("didSendDataWithTag")
}
func udpSocket(sock: GCDAsyncUdpSocket!, didNotSendDataWithTag tag: Int, dueToError error: NSError!) {
println("didNotSendDataWithTag")
}
}
Edit:
Added forgotten code line.
I finally got it to work with this socket setup:
func setupConnection(){
var error : NSError?
socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: dispatch_get_main_queue())
socket.bindToPort(PORT, error: &error)
socket.connectToHost(SERVER_IP, onPort: PORT, error: &error)
socket.beginReceiving(&error)
send("ping")
}
func send(message:String){
let data = message.dataUsingEncoding(NSUTF8StringEncoding)
socket.sendData(data, withTimeout: 2, tag: 0)
}
Apple Swift version 4.2.1 Well Tested UDP Example:-
STEP 1 :- pod 'CocoaAsyncSocket'
STEP 2 :- import CocoaAsyncSocket in your UIViewController.
STEP 3 :- UIViewController
import UIKit
import CocoaAsyncSocket
class ViewController: UIViewController {
#IBOutlet weak var btnOnOff: LightButton!
#IBOutlet weak var lblStatus: UILabel!
var inSocket : InSocket!
var outSocket : OutSocket!
override func viewDidLoad() {
super.viewDidLoad()
lblStatus.isHidden = true
inSocket = InSocket()
outSocket = OutSocket()
outSocket.setupConnection {
self.lblStatus.isHidden = false
}
}
#IBAction func btnLight(_ sender: Any) {
let signal:Signal = Signal()
self.outSocket.send(signal: signal)
}
}
STEP 4 :- Reciving Socket
//Reciving End...
class InSocket: NSObject, GCDAsyncUdpSocketDelegate {
//let IP = "10.123.45.2"
let IP = "127.0.0.1"
let PORT:UInt16 = 5001
var socket:GCDAsyncUdpSocket!
override init(){
super.init()
setupConnection()
}
func setupConnection(){
socket = GCDAsyncUdpSocket(delegate: self, delegateQueue:DispatchQueue.main)
do { try socket.bind(toPort: PORT)} catch { print("")}
do { try socket.enableBroadcast(true)} catch { print("not able to brad cast")}
do { try socket.joinMulticastGroup(IP)} catch { print("joinMulticastGroup not proceed")}
do { try socket.beginReceiving()} catch { print("beginReceiving not proceed")}
}
//MARK:-GCDAsyncUdpSocketDelegate
func udpSocket(_ sock: GCDAsyncUdpSocket, didReceive data: Data, fromAddress address: Data, withFilterContext filterContext: Any?) {
print("incoming message: \(data)");
let signal:Signal = Signal.unarchive(d: data)
print("signal information : \n first \(signal.firstSignal) , second \(signal.secondSignal) \n third \(signal.thirdSignal) , fourth \(signal.fourthSignal)")
}
func udpSocket(_ sock: GCDAsyncUdpSocket, didNotConnect error: Error?) {
}
func udpSocketDidClose(_ sock: GCDAsyncUdpSocket, withError error: Error?) {
}
}
STEP 5 :- Sending Socket..
//Sending End...
class OutSocket: NSObject, GCDAsyncUdpSocketDelegate {
// let IP = "10.123.45.1"
let IP = "127.0.0.1"
let PORT:UInt16 = 5001
var socket:GCDAsyncUdpSocket!
override init(){
super.init()
}
func setupConnection(success:(()->())){
socket = GCDAsyncUdpSocket(delegate: self, delegateQueue:DispatchQueue.main)
do { try socket.bind(toPort: PORT)} catch { print("")}
do { try socket.connect(toHost:IP, onPort: PORT)} catch { print("joinMulticastGroup not proceed")}
do { try socket.beginReceiving()} catch { print("beginReceiving not proceed")}
success()
}
func send(signal:Signal){
let signalData = Signal.archive(w: signal)
socket.send(signalData, withTimeout: 2, tag: 0)
}
//MARK:- GCDAsyncUdpSocketDelegate
func udpSocket(_ sock: GCDAsyncUdpSocket, didConnectToAddress address: Data) {
print("didConnectToAddress");
}
func udpSocket(_ sock: GCDAsyncUdpSocket, didNotConnect error: Error?) {
if let _error = error {
print("didNotConnect \(_error )")
}
}
func udpSocket(_ sock: GCDAsyncUdpSocket, didNotSendDataWithTag tag: Int, dueToError error: Error?) {
print("didNotSendDataWithTag")
}
func udpSocket(_ sock: GCDAsyncUdpSocket, didSendDataWithTag tag: Int) {
print("didSendDataWithTag")
}
}
STEP 6 :- Your Signal Data which you will Send/Recieve
import Foundation
struct Signal {
var firstSignal:UInt16 = 20
var secondSignal:UInt16 = 30
var thirdSignal: UInt16 = 40
var fourthSignal: UInt16 = 50
static func archive(w:Signal) -> Data {
var fw = w
return Data(bytes: &fw, count: MemoryLayout<Signal>.stride)
}
static func unarchive(d:Data) -> Signal {
guard d.count == MemoryLayout<Signal>.stride else {
fatalError("BOOM!")
}
var s:Signal?
d.withUnsafeBytes({(bytes: UnsafePointer<Signal>)->Void in
s = UnsafePointer<Signal>(bytes).pointee
})
return s!
}
}
Related
I am messing around with xmpp and I see that the connected delegate method never fires.
I have an openfire server running where I can login.
I also have Spark running where I can login.
Currently the delegate methods are firing in this order.
1. xmppStreamWillConnect
2. socketDidConnect
3. xmppStreamDidStartNegotiation
Nothing happens after this point.
Does anyone know why this happens?
Here is my connection..
let jId = XMPPJID(string: "admin#127.0.0.1")
ChatManager(jID: jId!, host: "127.0.0.1", password: "openfire")
Then inside the chat manager..
import Foundation
import XMPPFrameworkSwift
public final class ChatManager: NSObject {
var stream: XMPPStream!
var jID: XMPPJID
let host: String
let port: UInt16
let password: String
init(jID: XMPPJID, host: String, port: UInt16 = 32876, password: String) {
self.jID = jID
self.host = host
self.port = port
self.password = password
// Setup the XMPPStream
stream = XMPPStream()
stream.hostName = self.host
stream.hostPort = self.port
stream.myJID = self.jID
stream.startTLSPolicy = .allowed
super.init()
stream.addDelegate(self, delegateQueue: DispatchQueue.main)
connect()
}
private func connect(){
if !self.stream.isDisconnected {
}
let timeoutInterval: TimeInterval = 5.0
do {
try stream.connect(withTimeout: XMPPStreamTimeoutNone)
} catch {}
}
}
extension ChatManager: XMPPStreamDelegate {
public func xmppStreamDidSecure(_ sender: XMPPStream) {
print("Secured...")
}
public func xmppStreamDidStartNegotiation(_ sender: XMPPStream) {
print("Negotiation Started..")
}
public func xmppStream(_ sender: XMPPStream, willSecureWithSettings settings: NSMutableDictionary) {
print("Will secure...")
print("Settings: \(settings)")
}
public func xmppStream(_ sender: XMPPStream, didReceive trust: SecTrust, completionHandler: #escaping (Bool) -> Void) {
print("Recieved trust")
}
public func xmppStreamWillConnect(_ sender: XMPPStream) {
print("Attempting to connect...")
}
public func xmppStreamDidConnect(_ sender: XMPPStream) {
print("Connected")
try! stream.authenticate(withPassword: password)
}
public func xmppStreamConnectDidTimeout(_ sender: XMPPStream) {
print("Connection timeout")
}
public func xmppStreamWasTold(toAbortConnect sender: XMPPStream) {
print("Abortion connect")
}
public func xmppStreamDidAuthenticate(_ sender: XMPPStream) {
print("Stream: Authenticated")
}
public func xmppStream(_ sender: XMPPStream, didNotAuthenticate error: DDXMLElement) {
print("Stream: Not Authenticated")
}
public func xmppStream(_ sender: XMPPStream, socketDidConnect socket: GCDAsyncSocket) {
print("Connected socket")
}
}
Console Output
Refer to this post I have some issues while receiving data from GCDAsyncSocket and can't find a working Swift example.
import UIKit
import CocoaAsyncSocket
class DiscoveryViewControllerTest: UIViewController, GCDAsyncSocketDelegate{
let host = "192.168.55.1"
let port:UInt16 = 4000
let cmdDeviceInformation = "?0600\r";
let cmdDeviceIStandByeExit = "?060B\r";
let cmdDeviceIStandByeEnter = "?060A\r";
var mSocket: GCDAsyncSocket!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("Started wifi scanning!\n")
mSocket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main)
do {
try mSocket.connect(toHost: host, onPort: port)
} catch let error {
print(error)
}
print("Connecting to instrument...!\n")
}
public func socket(_ socket: GCDAsyncSocket, didConnectToHost host: String, port p:UInt16){
print("didConnectToHost!\n");
let data = cmdDeviceIStandByeEnter.data(using: .utf8)
print("TX: ", terminator: " ")
print(data! as NSData)
mSocket.write(data!, withTimeout:10, tag: 0)
mSocket.readData(withTimeout: -1, tag: 0) //This line was missing!
}
public func socket(_ sock: GCDAsyncSocket, didWriteDataWithTag tag: Int) {
print("didWriteData");
}
public func socket(_ sock: GCDAsyncSocket, didReceive trust: SecTrust, completionHandler: #escaping (Bool) -> Void) {
print("didReceiveData")
let rxData:Data = Data()
mSocket.readData(to: rxData, withTimeout: 5, buffer: nil, bufferOffset: 0, tag: 0)
print("RX: ", terminator: " ")
print(rxData as NSData)
}
public func socket(_ sock: GCDAsyncSocket, didRead: Data, withTag tag:CLong){
print("didRead!");
}
public func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Error?) {
print("didDisconnect!")
}
}
The connecting and writing method is running but the "didReceive" Method is never called.
Console output:
Started wifi scanning!
Connecting to instrument...!
didConnectToHost!
TX: <3f303630 410d> didWriteData
EDIT
I solved my problem and changed the question code to a ready to use example.
I have found my fault. The clue is to enable reading just behind the mSocket.write() function call in socket didConnectToHost(). The complete function looks like this:
public func socket(_ socket: GCDAsyncSocket, didConnectToHost host: String, port p:UInt16){
print("didConnectToHost!\n");
let data = cmdDeviceInformation.data(using: .utf8)
print("TX: ", terminator: " ")
print(data! as NSData)
mSocket.write(data!, withTimeout:10, tag: 0)
mSocket.readData(withTimeout: -1, tag: 0) // Add this line
}
BTW: I edited my question to create a ready to use example for everyone.
I would like to write an iOS Swift app that connects to an UDP server locally.
Here is the code I wrote using a library called CocoaAsyncSocket, however when I run it it does crash.
I haven't found any similar high level API in Apple. The only thing I found is this documentation which suggest to us a higher level API.
Would you be able to point me towards a better library or towards resolving the bug I get?
import UIKit
import CocoaAsyncSocket
class OutputSocket: NSObject, GCDAsyncUdpSocketDelegate {
var serverIP = "127.0.0.1"
var port:UInt16 = 10000
var socket:GCDAsyncUdpSocket!
override init(){
super.init()
setupConnection()
}
func setupConnection(){
socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: DispatchQueue.main)
do {
try socket.bind(toPort: self.port)
}
catch {
print("binding error: ", error.localizedDescription)
}
let addressData = serverIP.data(using: String.Encoding.utf8)
do {
try socket.connect(toAddress: addressData!)}
catch
{
print("connecting error: ", error.localizedDescription)
}
do {
try socket.beginReceiving()
}
catch {
print("connecting error: ", error.localizedDescription)
}
}
func send(message:String){
let data = message.data(using: String.Encoding.utf8)
let addressData = serverIP.data(using: String.Encoding.utf8)
socket.send(data!, toAddress: addressData!, withTimeout: 2, tag: 0)
}
func udpSocket(_ sock: GCDAsyncUdpSocket, didConnectToAddress address: Data) {
print("didConnectToAddress");
}
func udpSocket(_ sock: GCDAsyncUdpSocket, didNotConnect error: Error?) {
print("didNotConnect \(error)")
}
func udpSocket(_ sock: GCDAsyncUdpSocket, didSendDataWithTag tag: Int) {
print("didSendDataWithTag")
}
func udpSocket(_ sock: GCDAsyncUdpSocket!, didNotSendDataWithTag tag: Int, dueToError error: Error!) {
print("didNotSendDataWithTag")
}
}
Error description:
When I run it it crashes here:
EDIT:
I have removed the IP address from the equation and now, when I run the following code I get "didNotSendDataWithTag":
let data = message.data(using: String.Encoding.utf8)
socket.send(data!, withTimeout: 2, tag: 0)
Any idea why?
The variable is not nil, I have a good connection and the url is correct but no delegate methods are being called. Also I am implementing WebSocketDelegate
let socket = WebSocket(url: NSURL(string: "UrlHere:port/")!)
socket.delegate = self;
socket.connect()
if socket.isConnected {
print("websocket is connected")
}
func websocketDidConnect(ws: WebSocket) {
print("websocket is connected")
}
func websocketDidDisconnect(ws: WebSocket, error: NSError?) {
if let e = error {
print("websocket is disconnected: \(e.localizedDescription)")
} else {
print("websocket disconnected")
}
}
func websocketDidReceiveMessage(ws: WebSocket, text: String) {
print("Received text: \(text)")
}
func websocketDidReceiveData(ws: WebSocket, data: NSData) {
print("Received data: \(data.length)")
}
func websocketDidReceivePong(socket: WebSocket) {
print("Got pong!")
}
Socket should be a property or variable of your class to make sure it sticks around.
If you allocate it just on a function stack it will fall out of scope and the delegates will never get called
Here is the code that I have used in my project just in case
import UIKit
//import WebSocket
import Starscream
class ViewController: UIViewController,WebSocketDelegate,WebSocketPongDelegate {
#IBOutlet weak var wsURL: UITextField!
#IBOutlet weak var wsConsole: UITextView!
#IBOutlet weak var wsMessage: UITextField!
var socket:WebSocket!
override func viewDidLoad() {
super.viewDidLoad()
// var webSocketObj:WebSocket = WebSocket()
// webSocketObj.ipAddressText = "10.12.1.101"
// webSocketObj.portText = "8888"
// webSocketObj.dataToSendText = "hi"
// webSocketObj.dataRecievedTextView = ""
// webSocketObj.connectedLabel = ""
// webSocketObj.connectToServer()
wsURL.text="ws://10.12.1.101:8888/"
wsMessage.text="Hi"
self.navigationItem.leftBarButtonItem?.title="Connect"
self.navigationItem.rightBarButtonItem?.enabled=false
// Do any additional setup after loading the view, typically from a nib.
}
func websocketDidConnect(socket: WebSocket){
wsConsole.text = wsConsole.text .stringByAppendingString("\n websocket got connected")
self.navigationItem.leftBarButtonItem?.title="Disconnect"
self.navigationItem.rightBarButtonItem?.enabled=true
}
func websocketDidDisconnect(socket: WebSocket, error: NSError?){
wsConsole.text = wsConsole.text .stringByAppendingString("\n websocket got disconnected")
self.navigationItem.leftBarButtonItem?.title="Connect"
self.navigationItem.rightBarButtonItem?.enabled=false
}
func websocketDidReceiveMessage(socket: WebSocket, text: String){
wsConsole.text = wsConsole.text .stringByAppendingString("\n websocket got a message from server:").stringByAppendingString(text)
}
func websocketDidReceiveData(socket: WebSocket, data: NSData){
print("websocket received data",data)
}
#IBAction func writeText(sender: UIBarButtonItem) {
wsConsole.text = wsConsole.text .stringByAppendingString("\n Client sent a message:").stringByAppendingString(wsMessage.text!)
socket.writeString(wsMessage.text!)
self.view .endEditing(true)
}
#IBAction func disconnect(sender: UIBarButtonItem) {
self.view .endEditing(true)
if socket == nil{
connect(sender)
}
else if socket.isConnected {
socket.disconnect()
} else {
connect(sender)
}
}
func connect(sender:UIBarButtonItem){
socket = WebSocket(url: NSURL(string:wsURL.text!)!)
socket.delegate = self
socket.connect()
}
func websocketDidReceivePong(socket: WebSocket){
wsConsole.text = wsConsole.text .stringByAppendingString("\n websocket received pong")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is the link to storyboard just in case if you want
currently i am making chat application using Web Socket.
My question is How to Call Web Service in Web Socket ?
In iOS using swift you can use two Cocoapods Library which makes your work hassle free and
1) Starscream
2) RocketSocket
With reference to Starscream follow are very handy example:
import UIKit
import Starscream
class ViewController: UIViewController, WebSocketDelegate {
var socket: WebSocket!
override func viewDidLoad() {
super.viewDidLoad()
var request = URLRequest(url: URL(string: "http://localhost:8080")!)
request.timeoutInterval = 5
socket = WebSocket(request: request)
socket.delegate = self
socket.connect()
}
// MARK: Websocket Delegate Methods.
func websocketDidConnect(socket: WebSocketClient) {
print("websocket is connected")
}
func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {
if let e = error as? WSError {
print("websocket is disconnected: \(e.message)")
} else if let e = error {
print("websocket is disconnected: \(e.localizedDescription)")
} else {
print("websocket disconnected")
}
}
func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {
print("Received text: \(text)")
}
func websocketDidReceiveData(socket: WebSocketClient, data: Data) {
print("Received data: \(data.count)")
}
// MARK: Write Text Action
#IBAction func writeText(_ sender: UIBarButtonItem) {
socket.write(string: "hello there!")
}
// MARK: Disconnect Action
#IBAction func disconnect(_ sender: UIBarButtonItem) {
if socket.isConnected {
sender.title = "Connect"
socket.disconnect()
} else {
sender.title = "Disconnect"
socket.connect()
}
}
}