сокеты — C ++, UDP, sendto нужна задержка для работы

Я программирую сервер ретрансляции UDP на C ++. Но у меня есть проблема.

У меня есть базовый цикл, который просто вызывает recvfrom(), проверяет наличие ошибок в пакете, затем считывает «цель» из пакета и использует sendto() на том же сокете, чтобы отправить пакет целевому клиенту, который также ретранслирует на том же сервере.

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

m_iSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bind(m_iSocket, (SOCKADDR*)&m_oSockAddress, sizeof(SOCKADDR_IN));
...
while(true) {
recvfrom(m_iSocket, (char*)m_pRecvBuffer, m_nBufferSize, 0, (SOCKADDR*)&remoteAddr, &remoteAddrLen);
...
sendto(m_iSocket, reinterpret_cast<char*>(rw.getData()), rw.getBufferSize(), 0, targets address , address size);
}

Есть идеи?

0

Решение

Есть идеи?

Скорее всего, ваши исходящие UDP-пакеты теряются, потому что где-то переполнен буфер. Наиболее вероятное место для его переполнения — собственный буфер исходящих данных вашего сокета; если это так, вы можете уменьшить количество отброшенных пакетов, позвонив setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, ...) чтобы увеличить размер исходящего буфера вашего сокета (то есть достаточно большой, чтобы отправка удерживала все пакеты, которые вы передаете через вызовы sendto () за один раз).

Если этого недостаточно для решения проблемы, то следующее, что вы можете сделать, — реализовать собственную буферизацию в приложении; то есть вместо того, чтобы просто вызывать sendto (), помещать пакетные данные в конец структуры данных FIFO, а затем вызывать sendto () только тогда, когда сокет select () готов к записи (и когда это происходит, вытолкните следующий пакет из головы FIFO и вызовите sendto () с этим). Таким образом, вы всегда отправляете данные только с той скоростью, с которой буфер сокета может их принять, вместо того, чтобы предполагать, что буфер сокета всегда будет достаточно большим, чтобы сразу принимать все, что вы на него бросаете.

(Другое место, где буфер может быть переполнен, находится в приемном буфере сокета принимающего приложения, в этом случае вызов setsockopt(s, SOL_SOCKET, SO_RCVBUF, ...) на сокете принимающего приложения также может помочь)

0

Другие решения

Целевой процесс не читает достаточно быстро, поэтому датаграммы удаляются, потому что его буфер приема сокета заполнен. Тогда возникает вопрос, что такое правильное смягчение:

  1. (Если вы можете) ускорить приемник.
  2. Добавьте задержку в ваш цикл. Это только перемещает проблему вниз по течению к тому, кто посылает вам эти дейтаграммы. Датаграммы, поступающие к вам, будут отброшены, когда ваш буфер получателя сокета заполнен.
  3. Ничего не делать. Это не твоя проблема; ваш код правильный.

Я рекомендую (1), если это возможно, и (3). Не добавляйте задержки в сетевой код. Они не решают проблемы: они только меняют их.

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

0

По вопросам рекламы [email protected]