Я использую UDP-сокет в iOS. Я испытываю очень странное поведение, когда устанавливаю его в неблокирующий режим и/или имитирую плохое соединение.sendto() некогерентное поведение в гнезде UDP
Чтобы установить сокет в неблокирующем режиме с обычным fcntl
:
fcntl(socketfd, F_SETFL, O_NONBLOCK);
Для имитации плохого соединения я использую Network Link Conditioneer с 5/5 в потере/из пакетов и 50KBps из предела (который гарантирует в моем случае, если буфер системы будет заполнен в какой-то момент).
Я отправляю данные с sendto()
, и я звоню с clock()
и printf()
.
Вот данные из моих тестов, данные в мс:
- блокировки, хорошее соединение:
min 0
/max 929
//std 111
- блокировка, плохое соединение:
min 0
/max 611
/avg 38
/std 84
- не блокировка, хорошее подключение:
min 0
/max 6244
/avg 601
/std 1071
- не блокировка, плохое соединение:
min 0
/max 5774
/avg 400
/std 747
Я также заметил, что в случае 2
есть много записей с 0 ms
, а это означает, что sendto()
немедленно вернулся, что объясняет низкий среднее и стандартное отклонение случая.
Во всех случаях sendto()
возвратил положительное значение, соответствующее количеству байтов, которые были запрошены для отправки.
Теперь, есть несколько вещей, которые я просто не могу понять:
- в блокирующем режиме, я ожидаю, что блокировать до тех пор, пока имеются системные буфера для хранения данных, кажется, что вместо этого данные отбрасывается (поскольку вызов немедленно возвращается)
- в неблокирующем режиме, я ожидаю
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))
Я понимаю, что UDP не предоставляет никаких гарантий. Я также понимаю, что нет контроля потока. То, что я не могу понять, - это то, почему время для вызова sendto() сильно варьируется в зависимости от качества соединения, и я не могу понять, почему он изменяется в том, как он это делает. Есть ли способ обнаружить, что пакеты были фактически сброшены системой из-за полного буфера передачи? Может ли этот буфер быть полностью заполнен, если нет контроля потока? –