奇怪的Winsock recv()减速

时间:2012-02-21 15:33:03

标签: sockets winsock recv slowdown stack

我正在写一个像Skype这样的小型VOIP应用程序,现在效果很好,但我遇到了一个非常奇怪的问题。

在一个线程中,我在一个while(true)循环中调用winsock recv()函数每次运行两次以从套接字获取数据。 第一个调用获得2个字节,将被转换为(短),而第二个调用获取消息的其余部分,如下所示:

  

完整消息:[2 Byte Header |消息,长度由2Byte标题确定

这些数据包的周长约为49 /秒,约为3000字节/秒。

这些数据包的内容是转换为wave的音频数据。

使用ioctlsocket()我确定插槽上有一些数据,或者我收到的每条“消息”都没有(2字节+数据)。如果在我在线程的while(true) loop内收到消息后,套接字上有某些内容,则会收到该消息,但会被丢弃以防止堆叠延迟。

这个概念非常有效,但问题出在这里:

当我的VOIP程序正在运行时,当我平行下载(例如通过浏览器)文件时,套接字上总是会堆积太多数据,因为在下载时,recv() loop似乎实际上变慢了。除了实际的上传/下载之外,每次下载/上传都会发生这种情况。

我不知道这种行为来自何处,但当我实际取消除应用程序的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);}

1 个答案:

答案 0 :(得分:1)

无需使用ioctlsocket()来丢弃数据。这表明您的协议设计存在错误。假设您正在使用TCP(您没有说),如果您的2byte标头始终准确,则不应该有任何剩余数据。读取2byte标头然后读取指定的字节数后,接收到的下一个字节构成您的下一条消息,不应仅因为它存在而被丢弃。

ioctlsocket()报告更多可用字节的事实意味着您接收的消息比从套接字读取消息的速度快。让您的阅读代码运行得更快,不要因为速度慢而丢失好的数据。

您的阅读模式效率不高。您应该使用更大的缓冲区来读取套接字中的更多原始数据,而不是读取2个字节,然后是X个字节,然后是2个字节,依此类推(使用ioctlsocket()来了解可用的字节数,然后一次读取至少多个字节并将它们附加到缓冲区的末尾),然后在缓冲区中解析尽可能多的完整消息,然后从套接字读取更多原始数据再次。您一次可以读取的数据越多,接收数据的速度就越快。

为了帮助加快代码的速度,请不要直接处理循环内的消息。而是在另一个线程中进行处理。让读取循环将完整的消息放入队列并返回读取,然后在消息可用于处理时从队列中拉出处理线程。