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.
Related
I am trying to implement swift socket in my application. I am pretty new to socket programming. I have used
https://github.com/swiftsocket/SwiftSocket
for socket connection. I had create NSObject class for Server Connection.
I want Server connected through out my whole application, But Server is disconnected while I'm moving into another ViewController.
class SocketGLobal : NSObject
{
func Connect()
{
let client = TCPClient(address: "www.apple.com", port: 80)
switch client.connect(timeout: 1) {
case .success:
switch client.send(string: "GET / HTTP/1.0\n\n" ) {
case .success:
guard let data = client.read(1024*10) else { return }
if let response = String(bytes: data, encoding: .utf8) {
print(response)
}
case .failure(let error):
print(error)
}
case .failure(let error):
print(error)
}
}
}
I faced the same problem. So I created the custom ViewController and used GCDAsyncUdpSocket for socket connection. In your pod file add pod 'CocoaAsyncSocket' to use GCDAsyncUdpSocket. Here is the code snippet for custom ViewController.
import CocoaAsyncSocket
class CustomViewController: UIViewController, GCDAsyncUdpSocketDelegate {
//MARK: VARIABLE DECLARATION **********
var _udpSocket: GCDAsyncUdpSocket?
var udpSocket: GCDAsyncUdpSocket? {
get {
if _udpSocket == nil {
let port = 80
let sock = GCDAsyncUdpSocket(delegate: self, delegateQueue: DispatchQueue.main)
do {
sock.setIPv6Enabled(false)
// sock?.setIPv4Enabled(true)
// sock?.setPreferIPv4()
try sock.enableBroadcast(true)
try sock.bind(toPort: UInt16(port))
try sock.beginReceiving()
} catch let err as NSError {
print(">>> Error while initializing socket: \(err.localizedDescription)")
sock.close()
return nil
}
_udpSocket = sock
}
return _udpSocket
}
set {
_udpSocket?.close()
_udpSocket = newValue
}
}
//MARK: UDP SERVICES *********
//Start UDP Receiver
func startUDPService(){
guard udpSocket != nil else {
return
}
}
//Stop UDP Receiver
func closeUDPService(){
if udpSocket != nil {
udpSocket?.close()
udpSocket = nil
}
}
//MARK: HANDLING OF RECEIVED DATA **********
func udpSocket(_ sock: GCDAsyncUdpSocket, didReceive data: Data, fromAddress address: Data, withFilterContext filterContext: Any?) {
var hostPtr : NSString? = nil
GCDAsyncUdpSocket.getHost(&hostPtr, port: &send_port, fromAddress: address)
var receivedText = ""
if let stringData = String(data: data as Data, encoding: String.Encoding.utf8) {
receivedText = stringData
}
print("Data received: \(String(describing: hostPtr)), \(receivedText)")
}
}
In your each ViewController implement as follows:
import UIKit
class YourViewController: CustomViewController {
//MARK: LIFE CYCLE METHODS **********
override func viewWillAppear(_ animated: Bool) {
//MARK: START UDP SERVICE
self.startUDPService()
}
override func viewWillDisappear(_ animated: Bool) {
//MARK: STOP UDP SERVICE
self.closeUDPService()
}
}
I hope this will help you.
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?
I was trying connect to a host. I've tried using tls options, or even reading the example of simplehtpp in this git. But in swift 3 why it cants called ?
My log inside any delegate method isn't called . I change my host with anything, same result
class FGSocket: NSObject, GCDAsyncSocketDelegate {
let reachability = Reachability()!
let Log = Logger()
var socket: GCDAsyncSocket!
func connectToHub() {
Log.info("*** Connecting to Socket ***")
self.socket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main )
do {
try self.socket.connect(toHost: "google.com", onPort: UInt16(80), withTimeout: 60)
let hubApi : NSString = "google.com"
let manuallyTrust : NSNumber = true
Log.info("*** Got to here is connected ?***", self.socket.isConnected)
//Manually trust
let options = [
GCDAsyncSocketManuallyEvaluateTrust : manuallyTrust
//GCDAsyncSocketSSLPeerID : hubApi
] as [String : NSObject]
Log.info("Requesting StartTLS with options:\n", options);
self.socket!.startTLS(options)
} catch {
Log.error("Error", terminator: "Got error 😱😱😱\n")
}
Log.info("*** Got to here is connected ?***", self.socket.isConnected)
}
func socketDidSecure(_ sock: GCDAsyncSocket) {
Log.info("*** Did Secure to Host ***")
}
func socket(_ sock: GCDAsyncSocket, didConnectToHost host: String, port: UInt16) {
Log.info("*** Did Connect to Host ***")
}
func socket(_ sock: GCDAsyncSocket, didConnectTo url: URL){
Log.info("*** Did Connect to Url ***")
}
func socket(_ sock: GCDAsyncSocket, didAcceptNewSocket newSocket: GCDAsyncSocket) {
Log.info("*** Accept new Socket ***")
}
}
I have an application in which i have to send data to server using socket connection and read data which will send by server. I am using AsyncSocket class for write and read data. I got success to write data on server and server can see the data which was send by application. Now, problem is that whenever server send some data to application then how can i receive those data using AsyncSocket class. Below is my code. I put delegates method for reading data but it never called.
var socket = AsyncSocket()
socket = AsyncSocket(delegate: self)
self.socketConnect()
func socketConnect() {
do {
try socket?.connectToHost("IP Address", onPort: 6968)
} catch _ as NSError {
}
}
//MARK: - AsyncSocket Delegates method
func onSocket(sock: AsyncSocket!, didConnectToHost host: String!, port: UInt16) {
print("Connected to host : \(host) with Port : \(port)")
let alert:UIAlertController = UIAlertController(title: "Connected", message: "Host:\(host) ** Port:\(port)", preferredStyle:.Alert)
self.presentViewController(alert, animated: true, completion: nil)
let action:UIAlertAction = UIAlertAction(title: "Ok", style: .Default) { (UIAlertAction) -> Void in
print("Ok Pressed")
}
alert .addAction(action)
let dict = ["iUserId":"100","iRideId":"276","type":"client"] // For client side
var jsonString = NSString()
do {
let data = try NSJSONSerialization.dataWithJSONObject(dict , options: NSJSONWritingOptions.PrettyPrinted)
jsonString = NSString(data: data, encoding: NSUTF8StringEncoding)!
}catch let error as NSError {
print(error)
}
let reqData = jsonString.dataUsingEncoding(NSUTF8StringEncoding)
socket.writeData(reqData, withTimeout: 1.0, tag: 100)
}
func onSocket(sock: AsyncSocket!, didReadPartialDataOfLength partialLength: UInt, tag: Int) {
print("Read partial data")
}
func onSocket(sock: AsyncSocket!, didWriteDataWithTag tag: Int) {
print("Data write successfully")
}
func onSocket(sock: AsyncSocket!, didReadData data: NSData!, withTag tag: Int) {
print("Data read successfully")
}
func onSocket(sock: AsyncSocket!, willDisconnectWithError err: NSError!) {
print("Socket disconnect with error :\(err.description)")
}
func onSocket(sock: AsyncSocket!, didAcceptNewSocket newSocket: AsyncSocket!) {
print("Accept new socket")
}
I have found answer for my self. What i have missed is that i have to put readdata line when socket is connected to host. So after write this didReadData method will be called and in that method also have to write a single line code that i wrote in didConnectToHost method.
func socket(sock: GCDAsyncSocket!, didConnectToHost host: String!, port: UInt16) {
print("Connected to host : \(host) with Port : \(port)")
socket.readDataWithTimeout(-1, tag: 0)
}
func socket(sock: GCDAsyncSocket!, didReadData data: NSData!, withTag tag: Int) {
print("Data read successfully")
socket.readDataWithTimeout(-1, tag: 0)
}
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!
}
}