Реализация прослушивателя UDP в Swift?

Я пытался несколько перепроектировать проект для обнаружения устройств Logitech Harmony Hub в моей сети и опубликовал этот вопрос, чтобы узнать, может ли кто-нибудь помочь мне понять трансляцию UDP. В ответе поясняется, что я реализовал часть отправить широковещательной рассылки UDP, но ничего не реализовал для "прослушивания" ответов. И вот где я борюсь. Вот мой код отправить;

import UIKit
import CocoaAsyncSocket

class ViewController: UIViewController, GCDAsyncUdpSocketDelegate {

var address = "255.255.255.255"
var port:UInt16 = 5224
var socket:GCDAsyncUdpSocket!
var socketReceive:GCDAsyncUdpSocket!
var error : NSError?

override func viewDidLoad() {
super.viewDidLoad()

let message = "_logitech-reverse-bonjour._tcp.local.\n61991".dataUsingEncoding(NSUTF8StringEncoding)

socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: dispatch_get_main_queue())
socket.sendData(message, toHost: address, port: port, withTimeout: 1000, tag: 0)

    do {
        try socket.enableBroadcast(true)
    } catch {
        print(error)
    }

}

func udpSocket(sock: GCDAsyncUdpSocket!, didConnectToAddress address: NSData!) {
    print("didConnectToAddress");
}

func udpSocket(sock: GCDAsyncUdpSocket!, didNotConnect error: NSError!) {
    print("didNotConnect \(error)")
}

func udpSocket(sock: GCDAsyncUdpSocket!, didSendDataWithTag tag: Int) {
    print("didSendDataWithTag")
} 

func udpSocket(sock: GCDAsyncUdpSocket!, didNotSendDataWithTag tag: Int, dueToError error: NSError!) {
    print("didNotSendDataWithTag")
}

func udpSocket(sock: GCDAsyncUdpSocket!, didReceiveData data: NSData!, fromAddress address: NSData!, withFilterContext filterContext: AnyObject!) {

var host: NSString?
var port1: UInt16 = 0
GCDAsyncUdpSocket.getHost(&host, port: &port1, fromAddress: address)
print("From \(host!)")

let gotdata: NSString = NSString(data: data!, encoding: NSUTF8StringEncoding)!
print(gotdata)

    }

}

Я вижу, что у меня есть код для обработки ответа (в didReceiveData), но я не уверен, что мне нужно реализовать, чтобы начать прослушивание;

  • Нужно ли мне «привязываться» к порту слушателя (в данном случае 61991)?
  • Нужно ли мне "присоединяться к многоадресной группе"? И если да, то по какому адресу? Я попытался сделать это на «255.255.255.255», что создает ошибку setSocketOpt() при сборке.
  • Я знаю, что мне нужно вызвать beginReceiving(), и могу ли я сделать все это на socket, или мне нужно создать отдельный сокет для прослушивания?

Изменить: решено

Приведенный ниже ответ абсолютно помог мне решить проблему. Похоже, я не получил ответа, потому что не полностью реализовал средства обработки входящего ответа.

Согласно коду, указанному в ответе ниже, я добавил следующее:

// Setup the other socket (used to handle the response from the Harmony hub)
    otherSocket = GCDAsyncSocket(delegate: self, delegateQueue: dispatch_get_main_queue())

    do {

        // Accept connections on port 61991
        try otherSocket.acceptOnPort(61991)

    } catch {

        // Handle any errors here
        print(error)
    }

Я также установил этот контроллер как GCDAsyncSocketDelegate, что, похоже, помогло. Мне удалось прочитать ответ в didReadData.


person ZbadhabitZ    schedule 13.02.2016    source источник


Ответы (1)


Следующие изменения кода позволили мне получать UDP-пакеты, которые я отправлял с моего Mac с помощью netcat, но мой концентратор Harmony, похоже, ничего не отправлял, поэтому я не уверен, что отправляемые данные верны.

override func viewDidLoad() {
super.viewDidLoad()

let message = "_logitech-reverse-bonjour._tcp.local.\n61991".dataUsingEncoding(NSUTF8StringEncoding)

socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: dispatch_get_main_queue())


    do {
        try self.socket.bindToPort(61991)
        try self.socket.beginReceiving()
        try socket.enableBroadcast(true)
        socket.sendData(message, toHost: address, port: port, withTimeout: 1000, tag: 0)
    } catch {
        print(error)
    }

}

Из командной строки вы можете протестировать получение с помощью команды

echo -n "hello" | nc -4u -w1 x.x.x.x 61991
person Paulw11    schedule 13.02.2016
comment
Привет @Paulw11. Спасибо, что разъяснили это. Используя ваш код, я также могу получать сообщения, отправленные через терминал, и получать их на определенный порт в моем приложении. У меня такой же опыт с Harmony Hub. В качестве теста я сделал try self.socket.bindToPort(5224) в своем приложении и использовал приложение Harmony на своем iPhone/в той же сети Wi-Fi, чтобы притвориться, что нашел новый концентратор. Он отправил сообщение в форме _logitech-reverse-bonjour._tcp.local.\nXXXXX, хотя XXXXX каждый раз менялся на другой порт. - person ZbadhabitZ; 16.02.2016
comment
Кроме того, @Paulw11 - я действительно обнаружил, что проект NODE.JS, на котором я пытаюсь основывать этот проект, теперь не может найти мой уже установленный Harmony Hub (на прошлой неделе он смог это сделать). Я не уверен в точных шагах, но похоже, что запуск проекта NODE.JS позволяет ему найти концентратор один раз, а затем концентратор больше не отвечает на широковещательные передачи UDP, пока он не будет сброшен (отключен и снова подключен). Я все еще пытаюсь понять это. - person ZbadhabitZ; 16.02.2016
comment
После этого я понимаю, что приложение iOS не получает ответа от Harmony Hub. В качестве теста я попытался запустить скрипт node.js для обнаружения Harmony Hubs на другом компьютере, и я могу подтвердить, что отправляемое сообщение — это то, что используется в этом коде. Однако похоже, что проект node.js фактически создает свой собственный сервер (на сервере responseCollector.js), который получает ответ от Harmony; это не просто прослушивание порта 61991, если это возможно. - person ZbadhabitZ; 19.02.2016
comment
Код в этом ответе такой же, как и в responseCollector.js, с той лишь разницей, что порт 61991 жестко запрограммирован, как и в исходной трансляции, в то время как responseCollector.js использует порт, указанный в переменной. С помощью команды nc я подтвердил, что приложение прослушивает этот порт. - person Paulw11; 19.02.2016
comment
Привет @Paulw11. Извините, я не ясно выразился. Что мне кажется интересным, так это то, что если я отправляю сообщение на порт 61991 (либо через приложение iOS, либо с помощью команды nc), сценарий node.js не получает сообщение, хотя он последовательно получает ответ от Harmony Hub каждый раз. Я пытался отправить сообщение на широковещательный адрес и непосредственно на IP-адрес компьютера, на котором запущен скрипт node.js, но я не могу заставить его принять его, как это происходит с ответом Harmony Hub. Почти как ответ Harmony Hub или скрипт node.js не просто отправляет/получает на 61991. - person ZbadhabitZ; 19.02.2016
comment
Код node.js не использует фиксированный порт 61991, как у вас; вам нужно знать, какой порт код node.js отправляет в сообщении и, следовательно, прослушивает, а затем отправляет на этот порт. - person Paulw11; 19.02.2016
comment
Я понимаю. Я запускал файл Discover.js в папке примеров, который, похоже, использует порт 61991 (откуда я получил порт в первую очередь). - person ZbadhabitZ; 19.02.2016
comment
Я заработал. Редактирование моего вышеуказанного вопроса с кодом, используемым для решения проблемы. Ваша помощь была невероятно оценена. - person ZbadhabitZ; 19.02.2016