最近在做一套实时视频转发的程序,要在外网转输。加了一个中转服务器(IOCP)模型的。现在的问题是:如果我把视频数据划分成小于MTU值(512-1460)的大小传输的话一切正常,只是返回好多次GetQueuedCompletionStatus,吞吐量有所下降,丢帧严重。如果一次投递一帧的话(大小3000-20000字节)一开始是正常的,大概传了1MB左右的数据就缰死了。不知是什么原因。程序用互斥量控制,即:投递一帧数据之前看有没有正在执行WSASend投递中IO(互斥量大于0),如果为0就加1。把当前帧投递出去,否则丢掉当前帧。直到GetQueuedCompletionStatus查询到所有数据都已经投递出去之后就再次把互斥量减1变成0。感觉逻辑上没有什么问题啊,头都搞大了。另外以上方式在tcp 80端口下也能正常工作的,其他端口都在一分钟左右就死了:接收端收不到数据,发送端不在发送。过了几钟后GetQueuedCompletionStatus 查询到WSAsend了0字节关闭连接了。以下是部分代码:采集卡压缩出一帧数据,直接发起一个WSASend
         WSABUF buffSend;
temp = g_pClientList; while(temp != NULL)//temp != NULL
{
temp2 = temp->pCtxtForward;
if(strcmp(temp->pUser->DvrName,dvrID)==0&&
temp->pUser->VideoChannelID == nChannel)
{
if(temp->pIOSendContext->state==0)
{
temp->pIOSendContext->state++;
memcpy(temp->pIOSendContext->Buffer, pBuf,dwIoSize);
temp->pIOSendContext->IOOperation = ClientIoWrite;
temp->pIOSendContext->nTotalBytes = dwIoSize;
temp->pIOSendContext->nSentBytes  = 0;
buffSend.len  = dwIoSize;
buffSend.buf = temp->pIOSendContext->Buffer; dwFlags = 0;
nRet = WSASend(
temp->Socket,
&buffSend, 1, &dwSendNumBytes,
dwFlags,
&(temp->pIOSendContext->Overlapped), NULL); if( nRet == SOCKET_ERROR)
{
e = WSAGetLastError();
if(ERROR_IO_PENDING ==e )
{
WriteLog(_T("[%d]SendDataToClient 发送阻塞,暂停发送.\n"),temp->Socket);
//myprintf(_T("发送阻塞,暂停发送: %d\n"), e);
}
else
{
temp->pIOSendContext->state = -1;
CloseClient(temp,FALSE);
//myprintf(_T("WSASend() failed: %d\n"), e);
WriteLog(_T("SendDataToClient WSASend() failed: %d\n"), e);
}
}
}
else if(temp->pIOSendContext->state>0)
{
WriteLog(_T("[%d]丢弃数据,大小:%d.\n"),temp->Socket,dwIoSize);
}
} temp = temp2;
}
IOCP内部:
case ClientIoWrite: //lpIOContext->IOOperation = ClientIoWrite;
lpIOContext->nSentBytes  += dwIoSize;
dwFlags = 0;
if( lpIOContext->nSentBytes < lpIOContext->nTotalBytes )
{
//WriteLog(_T("共计%d字节 上次发送了%d字节,有还剩余%d字节未发送\n"),lpIOContext->nTotalBytes,dwIoSize,lpIOContext->nTotalBytes-lpIOContext->nSentBytes); buffSend.buf = lpIOContext->Buffer + lpIOContext->nSentBytes;
buffSend.len =lpIOContext->nTotalBytes - lpIOContext->nSentBytes; nRet = WSASend(
lpPerSocketContext->Socket,
&buffSend, 1, &dwSendNumBytes,
dwFlags,
&(lpIOContext->Overlapped), NULL);
e = WSAGetLastError();
if( nRet == SOCKET_ERROR )
{
if( e != ERROR_IO_PENDING)
{
WriteLog(_T("ClientIoWrite WSASend() failed: %d\n"), e);
lpIOContext->state = -1;
CloseClient(lpPerSocketContext,FALSE);
}
}
}
else
{
//ZeroMemory(lpIOContext->Buffer,sizeof(lpIOContext->Buffer));
lpIOContext->state--;
}
break;