#ios #networking #tcp #client-server
#iOS #сеть #tcp #клиент-сервер
Вопрос:
У меня есть клиентское приложение iOS, которое создает NWConnection через TCP.
connection = NWConnection(host: hostTCP, port: portTCP, using: .tcp)
connection?.stateUpdateHandler =
{ [self] (newState) in
print("This is stateUpdateHandler:")
switch (newState)
{
case .ready:
print("State: Readyn")
self.sendTCP(messageToTCP)
self.receiveTCP()
case .setup:
print("State: Setupn")
case .cancelled:
print("State: Cancelledn")
case .preparing:
print("State: Preparingn")
default:
print("ERROR! State not definedn")
}
}
print("connectToTCP: Connection to server startedn")
connection?.start(queue: .global())
И функция receiveTCP () выглядит следующим образом:
func receiveTCP()
{
connection?.receiveMessage
{ (data, context, isComplete, error) in
if (isComplete)
{
print("Receive is complete")
if (data != nil)
{
let backToString = String(decoding: data!, as: UTF8.self)
print("Received message: (backToString)")
}
else
{
print("Data == nil")
}
}
else
{
self.receiveTCP()
}
}
}
Я использую инструмент командной строки в качестве серверного приложения, запущенного на моем MacBook, который прослушивает входящее соединение и отправляет / получает сообщения.
Отправка сообщений отлично работает из клиентского приложения iOS, но прием не работает. Также клиентское приложение отлично работает (как для отправки, так и для получения) через UDP. Что-то не так, что я здесь делаю?
В документации Apple в https://developer.apple.com/documentation/network/nwconnection/3020638-receivemessage
его упоминалось
Получение сообщений позволяет обрабатывать полные дейтаграммы или сообщения прикладного уровня без необходимости реконструировать поток. Если вы используете UDP, получение сообщения доставит единственную дейтаграмму. Если вы запрашиваете получение сообщения по протоколу, который в противном случае является неограниченным потоком байтов, например TCP или TLS, обратите внимание, что это не доставит никаких данных, пока поток не будет закрыт одноранговым узлом.
Что это значит «Если вы запрашиваете получение сообщения по протоколу, который в противном случае является неограниченным байтовым потоком, например TCP или TLS, обратите внимание, что это не доставит никаких данных, пока поток не будет закрыт одноранговым узлом».?
Кто-нибудь знает простой пример TCP для устройств iOS, который использует NWFramework для отправки и получения строковых данных на сервер и с сервера?
Ответ №1:
TCP — это потоковый протокол. Соединение представляет собой просто два потока байтов — отправка и получение. В TCP нет понятия «сообщение». Вашему приложению необходимо наложить некоторое обрамление на поток, чтобы извлечь из него структуру. например, вы можете отправить «hello n», «World n», «test n» в виде трех отдельных вызовов send
, но все эти данные могут быть отправлены в одном пакете адресату; TCPstack пытается оптимизировать использование сети, и более эффективно отправлять один пакет большего размера, чем несколько пакетов меньшего размера.
Аналогично, большой объем передаваемых данных send
может быть отправлен в виде нескольких пакетов, если объем данных превышает максимальную единицу передачи (MTU) сети. Данные, отправляемые через Интернет, могут быть даже разделены на меньшие пакеты, если встречается ссылка с меньшим MTU. Все, что гарантирует TCP, — это то, что отправленные байты будут доставлены в том порядке, в котором они были отправлены. Нет гарантии, сколько пакетов поступит.
Что это значит «Если вы запрашиваете получение сообщения по протоколу, который в противном случае является неограниченным байтовым потоком, например TCP или TLS, обратите внимание, что это не доставит никаких данных, пока поток не будет закрыт одноранговым узлом».?
Это означает, что вы не получите никакого сообщения, пока сервер не закроет TCP-соединение. Если ваш серверный код не закрывает соединение после отправки ответа, то receiveMessage
оно не будет завершено. Вы можете использовать receive(minimumIncompleteLength:maximumLength:completion:)
для получения ответа «порциями». Затем вам нужно будет повторно собрать их и извлечь ваше сообщение (например, ваше сообщение может заканчиваться новой строкой n
— вы должны просмотреть данные для символов новой строки, чтобы разделить полученные данные на отдельные сообщения.
Apple предоставляет NWProtocolFramer
протокол, позволяющий создавать код для анализа сообщений из потока TCP. Вы реализуете код, который соответствует NWProtocolFramerImplementation
и который работает с предоставленным NWProtocolFramer.Instance
для извлечения сообщений из потока и кодирования сообщений обратно в поток байтов.
Комментарии:
1. Большое спасибо за подробное объяснение. Использование receive(minimumIncompleteLength:MaximumLength: завершение:) решило мою проблему.