程序启动时要同步大量数据(几十M,每个包小于1K)到一客户端(局域网)。由于发送太频繁而崩溃。
比如:
for (int i = 0; i < 1000000; i++)
{
if ( SOCKET_ERROR == ::WSASend(m_socket, pBuffer->GetWSABUF(), 1, &dwSendNumBytes, dwFlags, pBuffer, NULL ) )
{
DWORD lastError = ::WSAGetLastError();

if ( WSAENOBUFS == lastError )
ASSERT(FALSE); // 系统崩溃
else if ( ERROR_IO_PENDING != lastError )
{
....;
}
}
}
崩溃时系统的所有网络连接断开,不能建立任何新连接,并有一定几率系统底层崩溃。经核实,系统“非分页内存”已被占满。
很多资料有描述这个相似的问题,但是没发现完美的解决办法。
现在的情况是:
1、不能简单地使用堵塞的发送,会妨碍其他连接的发送速度;
2、由于连接数庞大,不能使用每个连接一个线程的方式;
3、不是很希望斤斤计较的判断每一个send是否发送完,怕会降低效率。注意:这里是WSASend调用过快引起的,还没有调用很多WSARecv。是否能在非分页内存紧张的时候得到一个通知,以控制发送频率?还是有什么更好的办法?

解决方案 »

  1.   

    提供一个IoCompletionRoutine,并且在里面调用WSASend.这样每时每刻,系统最多只有一个WSASend正在进行.
      

  2.   

    if ( SOCKET_ERROR == ::WSASend(m_socket, pBuffer->GetWSABUF(), 1, &dwSendNumBytes, dwFlags, pBuffer, NULL ) )
    1 此处怎么发送的都是一个pBuff
    2 第5个参数LPWSAOVERLAPPED lpOverlapped 怎么填的是pBuff?
      

  3.   

    to redstorm_fyy():
      用的就是IoCompletionRoutine + WSASend。即时系统同时进行的WSASend只有一个(我没试过),但是系统缓存里面等待处理队列也是没有限制。毕竟网络带宽、客户端接受能力等不是无限的,而WSASend声称是立即返回,队列长了早晚有异常)to freebird001(自由鸟):
      例子代码~~不好意思~~Practise_Think(时代“过客”):
      回收了的,用了很久的代码,其他方面应该没问题。就是从来没发过这么快速而已。
      

  4.   

    每次WSASend可以申请一个或从Sendbuf队列中取一个SendBuf,申请时若不成功就不要再WSASend
      

  5.   

    解决思路
    1。增大操作系统网络buffer
    2。提高发送性能,使用raw socket
      

  6.   

    开N个线程,把连接平均分配到这N个线程中,每个线程用同步方式依次为每个连接调用send发送数据。
      

  7.   

    to redstorm_fyy():
      用的就是IoCompletionRoutine + WSASend。即时系统同时进行的WSASend只有一个...
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    if ( SOCKET_ERROR == ::WSASend(m_socket, pBuffer->GetWSABUF(), 1, &dwSendNumBytes, dwFlags, pBuffer, NULL ) )
                    ~~~~~~~~~~~~IoCompletionRoutine ???
    建议楼主再仔细看看异步Io模型
      

  8.   

    to redstorm_fyy():
      因为是例子代码,已经简化了很多东西,上面贴出来的代码是在完成端口取出任务后调用的数个函数中的一个函数中的一小部分。为了简单说明问题,加上循环想表示发的很多。呵呵,偶误导了~~to freebird001(自由鸟):
      发生WSAENOBUFS时,好像已经没有什么好办法恢复了,据说只能断开连接。这里的数据传输因为每一个包都很重要,所以不希望在发生错误时再尽量弥补。to alec626(月吻长河Blog:spaces.msn.com/filebase):
      1方法尝试过,我把socket的sendbuf设置为128M,没能测出变化。用的setsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, (char*)&nBufLen, nIntSize);返回值看起来是成功了。2方法听起来就怕,不过实在没辙我也只能用它了~~to Analyst():
      由于连接数实在太多(顶峰时有可能上千个),从来没试过这么多线程一起跑会怎么样:(
    偶被这个问题折磨了一个多星期了,快哭了~~
      

  9.   

    能到这种程度也真是牛了。
    试试IOCP,
      

  10.   

    if ( SOCKET_ERROR == ::WSASend(m_socket, pBuffer->GetWSABUF(), 1, &dwSendNumBytes, dwFlags, pBuffer, NULL ) )
    ~~~~~~~~~~~~IoCompletionRoutine ???
    楼主用的是IOCP吧(IOCP最好了),而不是IoCompletionRoutine.
    在使用pBuffer前申请内存用VirtualAlloc,申请不到就不WSASend,还会出WSAENOBUFS吗?