2012-02-21 4 views
0

Я пишу небольшое приложение VOIP, такое как Skype, которое сейчас работает неплохо, но я столкнулся с очень странной проблемой.Weird Winsock recv() slowdown

В одном потоке я вызываю в течение некоторого цикла (true) функцию winsock recv() дважды за каждый проход, чтобы получить данные из сокета. Первый вызов получает 2 байт, которые будут отлиты в (короткий), а второй вызов получает оставшуюся часть сообщения, которая выглядит как:

Полного сообщение: [2 байт заголовок | Сообщение, длина, определяемая заголовком 2Byte]

Эти пакеты круглые около 49/с, что будет около 3000 байт/с.

Содержание этих пакетов - это аудиоданные, которые преобразуются в волну.

С ioctlsocket() Я определяю, есть ли какие-либо данные в сокете или нет в каждом «сообщении», которое я получаю (2 байта + данных). Если что-то есть в сокете сразу после того, как я получил сообщение в пределах while(true) loop потока, сообщение будет получено, но оно будет отброшено, чтобы работать с задержкой нарастания.

Эта концепция работает очень хорошо, но вот проблема:

Хотя моя VOIP программа работает, и когда я паралельно загрузки (например, через браузер) файл, всегда получает слишком много данных, сложенных на сокете, т.к. при загрузке, recv() loop, похоже, замедляется. Это происходит в каждой ситуации загрузки/выгрузки, кроме фактической загрузки/загрузки voip.

Я не знаю, откуда взялось это поведение, но когда я фактически отменяю каждую загрузку, кроме трафика voip моего приложения, мои приложения снова работают отлично.

Если программа работает отлично, функция ioctlsocket() записывает 0 в переменную bytesLeft var, определенную в классе, откуда приходит функция приема.

Знает ли кто-нибудь, откуда это взялось? Я приложу мой получить функцию вниз:

std::string D_SOCKETS::receive_message(){ 

recv(ClientSocket,(char*)&val,sizeof(val),MSG_WAITALL); 
receivedBytes = recv(ClientSocket,buffer,val,MSG_WAITALL); 

if (receivedBytes != val){ 

    printf("SHORT: %d PAKET: %d ERROR: %d",val,receivedBytes,WSAGetLastError()); 
    exit(128); 
} 


ioctlsocket(ClientSocket,FIONREAD,&bytesLeft); 
cout<<"Bytes left on the Socket:"<<bytesLeft<<endl; 

if(bytesLeft>20) 
{ 
    // message gets received, but ignored/thrown away to throw away 
    return std::string(); 
} 
else 
    return std::string(buffer,receivedBytes);} 
+0

Учитывая, что ваша программа VOIP и другая программа разделяют одну и ту же полосу пропускания, не ожидалось бы, что большая загрузка другой программой замедлит прием данных вашей программы на какую-то сумму? Особенно, если вы используете TCP, а конфликт пропускной способности заставляет один из пакетов TCP вашего потока отбрасываться ... тогда отправителю придется отправить его повторно, и пока ваше приложение не увидит, что больше данных не поступит. Также TCP делает автоматическое дросселирование скорости передачи, чтобы избежать перегрузок, так что это также может быть фактором. Для VOIP часто лучше использовать UDP ... –

ответ

1

Там нет необходимости использовать ioctlsocket() отбрасывать данные. Это указывает на ошибку в вашем проекте протокола. Предполагая, что вы используете TCP (вы не сказали), не должно быть никаких данных, если ваш 2-байтовый заголовок всегда точен. После прочтения 2-байтового заголовка и последующего чтения указанного количества байтов, следующие байты, которые вы получаете после этого, составляют ваше следующее сообщение и не должны быть отброшены просто потому, что он существует.

Тот факт, что ioctlsocket() сообщает больше доступных байтов, означает, что вы получаете сообщения быстрее, чем вы их читаете из сокета. Сделайте код чтения быстрее, не выбрасывайте хорошие данные из-за вашей медлительности.

Ваша модель чтения не эффективна. Вместо того, чтобы читать 2 байта, затем X байты, затем 2 байта и т. Д., Вы должны вместо этого использовать более крупный буфер для чтения более сырых данных из сокета за один раз (используйте ioctlsocket(), чтобы узнать, сколько байтов доступно, а затем прочитайте , по крайней мере,, что много байтов за один раз и добавьте их в конец вашего буфера), а затем проанализируйте, как много полных сообщений находятся в буфере, а затем снова прочитайте больше сырых данных из сокета. Чем больше данных вы можете прочитать за раз, тем быстрее вы сможете получать данные.

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

+0

+1 для попытки изменения направления, ошибки ... «необычный» дизайн. –

+0

Большое вам спасибо за помощь! Я был в больнице в течение долгого времени, поэтому я не смог написать обратно. Я построил его, как сказал Реми Лебо, и он работает как шарм. Необходимо переключиться на UDP из-за того, что сказал Джереми Фризнер, из-за дросселирования отправки, потому что мое приложение явно не видит, что данные поступают, когда я загружаю, например. файл при прослушивании моей аудиопрограммы. – fludd

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

  • Нет связанных вопросов^_^