2012-02-21 3 views
0

내가 지금 아주 잘 작동 스카이프와 같은 약간의 VoIP 응용 프로그램을 쓰고 있어요,하지만 난 아주 이상한 문제로 실행했습니다. 이상한 윈속 RECV() 둔화

은 하나 개의 스레드에서, 나는 소켓에서 데이터를 가져 오기 위해 실행에 두 번 잠시 동안 (사실) 루프 내에서 윈속 ​​RECV() 함수를 호출하고 있습니다. | [2 바이트 헤더 :

전체 메시지 : 첫 번째 호출은 두 번째 호출과 같은 메시지의 나머지를 얻는 동안 (짧은)에 주조됩니다 2 바이트를 가져옵니다 메시지, 길이는 2Byte Header에 의해 결정됨]

이 패킷들은 대략 초당 4900 바이트이며, 약 3000 바이트/초의 라운드입니다.

이들 패킷의 콘텐츠는 웨이브로 변환 도착 오디오 데이터이다. ioctlsocket()

내가 소켓 여부를 각 "메시지"에서 일부 데이터가 어떠했는지를 결정 나는 (2 바이트 + 데이터)가 나타납니다. 스레드의 while(true) loop 내에 메시지를받은 직후에 소켓에 ​​뭔가가 있으면 메시지가 수신되지만 대기 시간을 상향 조정하지 못하게됩니다.

이 개념은 아주 잘 작동하지만, 문제는 여기에있다 :

내 VOIP 프로그램이 실행되는 동안 나는 평행 파일을 (예를 통해 브라우저를) 다운로드 할 때, 항상 있기 때문에, 소켓에 쌓인 너무 많은 데이터가 도착 다운로드하는 동안 recv() loop은 실제로 속도가 느려집니다. 이것은 실제 voip up/download 이외의 모든 다운로드/업로드 상황에서 발생합니다.

이 문제가 어디에서 오는지 모르겠어요,하지만 실제로 내 응용 프로그램의 VoIP 트래픽 이외의 모든 업/다운로드를 취소 할 때, 내 응용 프로그램을 다시 완벽하게 작동합니다.

프로그램이 완벽하게 실행하는 경우

ioctlsocket() 기능은 기능에서 제공받을 경우 클래스 내에서 정의의 bytesLeft의 VAR에 0을 기록합니다.

어디에서 왔는지 알고 있습니까? 아래 수신 기능을 첨부하겠습니다 :

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를 사용한다고 가정하면 2byte 헤더가 항상 정확하다면 데이터가 남아 있지 않아야합니다. 2 바이트 헤더를 읽은 다음 지정된 바이트 수를 읽은 후받은 다음 바이트는 다음 메시지를 구성하며 존재하기 때문에 단순히 버려져서는 안됩니다.

ioctlsocket()이 더 많은 바이트를 사용할 수 있다는 사실은 사용자가 소켓에서 읽는 것보다 더 빨리 메시지를 받는다는 것을 의미합니다. 독서 코드를 빠르게 실행하고, 느린 속도로 인해 좋은 데이터를 버리지 마십시오.

귀하의 독서 모델은 효율적이지 않습니다. 2 바이트, X 바이트, 2 바이트 등을 읽는 대신, 더 큰 버퍼를 사용하여 한 번에 소켓에서 더 많은 원시 데이터를 읽어야합니다 (사용 가능한 바이트 수를 알아 보려면 ioctlsocket()을 사용하고 읽은 다음 적어도 이상이 한 번에 많은 바이트를 버퍼의 끝에 추가 한 다음 소켓에서 많은 원시 데이터를 다시 읽으려면 많은 완료 메시지가 버퍼에있는 것으로 파싱합니다. 한 번에 읽을 수있는 데이터가 많을수록 데이터를 더 빨리받을 수 있습니다.

코드의 속도를 더욱 높이려면 루프 내부의 메시지도 직접 처리하지 마십시오. 대신 다른 스레드에서 처리하십시오. 읽기 루프가 전체 메시지를 큐에 넣고 다시 읽도록 한 다음 메시지를 처리 ​​할 수있을 때마다 큐에서 처리 스레드를 가져옵니다.

+0

+1 방향을 변경하려고 시도한 경우 오류 ... '비정상적인'디자인. –

+0

도움을 주셔서 대단히 감사합니다! 나는 오랫동안 병원에 갔었는데, 그래서 나는 다시 쓸 수 없었다. 나는 Remy Lebeau가 말했듯이 그것을 만들었고 그것은 매력처럼 작동합니다. Jeremy Friesner가 전송 대기로 인해 조절 되었기 때문에 UDP로 전환해야합니다. 예를 들어 내가 업로드 할 때 내 앱에서 데이터가 더 이상 수신되지 않아서. 내 오디오 프로그램을 시도하면서 파일. – fludd