2016-12-27 2 views
0

Я использую UDP-сокет в iOS. Я испытываю очень странное поведение, когда устанавливаю его в неблокирующий режим и/или имитирую плохое соединение.sendto() некогерентное поведение в гнезде UDP

Чтобы установить сокет в неблокирующем режиме с обычным fcntl:

fcntl(socketfd, F_SETFL, O_NONBLOCK); 

Для имитации плохого соединения я использую Network Link Conditioneer с 5/5 в потере/из пакетов и 50KBps из предела (который гарантирует в моем случае, если буфер системы будет заполнен в какой-то момент).

Я отправляю данные с sendto(), и я звоню с clock() и printf().


Вот данные из моих тестов, данные в мс:

  1. блокировки, хорошее соединение: min 0/max 929//std 111
  2. блокировка, плохое соединение: min 0/max 611/avg 38/std 84
  3. не блокировка, хорошее подключение: min 0/max 6244/avg 601/std 1071
  4. не блокировка, плохое соединение: min 0/max 5774/avg 400/std 747

Я также заметил, что в случае 2 есть много записей с 0 ms, а это означает, что sendto() немедленно вернулся, что объясняет низкий среднее и стандартное отклонение случая.

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

Теперь, есть несколько вещей, которые я просто не могу понять:

  1. в блокирующем режиме, я ожидаю, что блокировать до тех пор, пока имеются системные буфера для хранения данных, кажется, что вместо этого данные отбрасывается (поскольку вызов немедленно возвращается)
  2. в неблокирующем режиме, я ожидаю sendto() возвращать ошибку, когда он будет блокировать, а не из данных, кажется, что вызов блокируется до тех пор, пока на самом деле пространство для выполнения его

Th e поведение инвертируется, за исключением того, что sendto никогда не сообщает об ошибке.

Что я делаю неправильно?


Создание сокета:

int socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)); 
// error checks 
setsockopt(socketfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); 

int tos = 0xB8; // VOICE 
setsockopt(socketfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); 

int rc = fcntl(m_iSocket, F_SETFL, O_NONBLOCK); 
if (rc != 0) { 
    // error of fcntl is notified 
} 

Отправка:

sendto(socketfd, buffer, buffer_length, 0, (struct sockaddr *) &m_sRemoteHost, sizeof(m_sRemoteHost)) 

ответ

2

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

согласно UDP page on Wikipedia:

UDP является минимальным сообщение-ориентированный протокол уровня транспорта, который описано в RFC 768. UDP не предоставляет никаких гарантий верхнего протокола слоя для доставки сообщений и UDP слой не сохраняет состояние Сообщения UDP после отправки. По этой причине UDP иногда ссылается на как Ненадежный Протокол дейтаграмм.

+0

Я понимаю, что UDP не предоставляет никаких гарантий. Я также понимаю, что нет контроля потока. То, что я не могу понять, - это то, почему время для вызова sendto() сильно варьируется в зависимости от качества соединения, и я не могу понять, почему он изменяется в том, как он это делает. Есть ли способ обнаружить, что пакеты были фактически сброшены системой из-за полного буфера передачи? Может ли этот буфер быть полностью заполнен, если нет контроля потока? –

Смежные вопросы