Странное замедление Winsock recv () - PullRequest
0 голосов
/ 21 февраля 2012

Я пишу небольшое VOIP-приложение, такое как Skype, которое сейчас работает довольно хорошо, но я столкнулся с очень странной проблемой.

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

Complete Message: [2 Byte Header |Сообщение, длина которого определяется 2-байтовым заголовком.это превращается в волну.

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

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

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

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

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

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

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);}

1 Ответ

1 голос
/ 21 февраля 2012

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

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

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

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

...