2011-10-31 25 views
1

我能够通过套接字编程成功地发送一个静态类,对于少量数据工作正常,但在生产环境中,它冻结了一段时间,又一次开始发送数据,我无法弄清楚什么问题是什么?你能帮忙吗?代码如下。在Windows中的套接字编程发送数据冻结了一段时间,并延迟了一段时间?

  DWORD BytesCount; 
    WSABUF Buffer[1]; 
    DWORD Flag = 0; 

    Buffer[0].len = SendLength; 
    Buffer[0].buf = SendData; 
    if (WSASend(*socket, Buffer, 1, &BytesCount, Flag, NULL, NULL) != SOCKET_ERROR) 
    { 
     if (BytesCount != SendLength) 
      Result = -2; 
     else 
     { 
      if (ReturnAnswer) 
      { 
       int Res = 0, recBufStart; 
       DWORD RecvCount = 0, AllRecv = 0; 

       Buffer[0].len = ReceiveLength; 
       Buffer[0].buf = ReceiveData; 
       recBufStart = 0; 
       saAction = saReceive; 

       // We need to Receive until we get all the data. When WSARecv call might only return zero bytes 
       bool Stop = true; // true as we dont need to recieve anything from the server. 
       while (!Stop) 
       { 
        Res = WSARecv(*socket, &Buffer[recBufStart], (recBufStart == 0 ? 1 : 0), &RecvCount, &Flag, NULL, NULL); 
        if (Res == SOCKET_ERROR) 
         Stop = true; 
        else 
        { 
         AllRecv = AllRecv + RecvCount; 
         if (AllRecv == ReceiveLength || RecvCount == 0) 
          Stop = true; // Stop 
         else 
         { 
          Buffer[0].buf = &ReceiveData[AllRecv]; 
          Buffer[0].len = ReceiveLength - (AllRecv); 
          recBufStart = 0; 
         } 
        } 
       } 

       if (Res == SOCKET_ERROR) 
        Result = WSAGetLastError();     
      } 
     } 
    } 
    else 
     Result = WSAGetLastError();  
+0

“WSASend”还是“WSARecv”冻结了? –

+0

我正在使用WSASend,至于时间我没有收到任何东西,你可以看到布尔值设置为true。 – Ershad

回答

1

我不知道是否这可能是问题,但从WSASend Microsoft文档有以下几点:

当发出阻塞Winsock调用,如WSASend与lpOverlapped参数集为NULL,Winsock可能需要等待网络事件才能完成通话。

此外,您的接收代码似乎相当复杂。在什么情况下,recBufStart将不是0?我也不会使用变量“停止”。只需发出break语句即可退出while循环。

编辑:更仔细地看一下你的接收代码,你在while(!Stop)之前设置Stop为true,即while(Stop == false)。所以它不会去WSARecv。这是故意的吗?如果是这样,微软的解释和下面的答案似乎表明你的问题,即你不断发送和Winsock必须等待,才能发送更多的数据。

+0

好的,故意我现在没有收到任何数据,问题你说的话似乎是正确的,那么为避免这种情况需要做些什么呢?我在创建套接字时使用select,并在超时错误之间进入。 – Ershad

+0

我还没有看到只发送数据而没有收到的代码。我认为您需要从发送给您的对等点获得某些回报,并且此时您可能会获得解除WSASend的网络事件。只是为了测试简单地做一个WSASend后跟一个WSARecv。使用Berkeley套接字接口而不是Microsoft接口可能更容易,以避免所有这些重叠的I/O内容,即发送而不是WSASend,套接字,而不是WSASocket和recv,而不是WSARecv。 – rushman

0

您正在使用WSASend并且WSARecv处于阻塞模式(最后两个参数为NULL)。这意味着,只要填充了TCP/IP堆栈缓冲区,下一次对WSASend的调用就会阻塞,直到缓冲区中再次出现空间(即数据已发出)。

您最好使用异步调用和I/O completion ports

+0

我正在使用这个并且超时,这是否会导致问题。代码如下。如果(选择(0,NULL,&ConnectSockets,NULL,&超时)== SOCKET_ERROR) \t { \t \t LogToEventLog(EVENTLOG_WARNING_TYPE,EVENTID_WINSOCK_ERROR,_T( “主服务器连接失败 - 与误差%ld的一个选择呼叫”),WSAGetLastError( )); \t \t Close(SocketPrimary,TRUE); \t \t return false; \t} \t其他 \t { \t \t如果(ConnectSockets.fd_count == 0) \t \t { \t \t \t LogToEventLog(EVENTLOG_WARNING_TYPE,EVENTID_WINSOCK_ERROR,_T( “主服务器连接失败 - 已逾时连接...” )); \t \t \t Close(SocketPrimary,TRUE); \t \t \t return false; \t \t} \t} – Ershad

0

如果应用程序发送的数据块大于套接字的发送缓冲区大小,TCP堆栈可能会阻塞应用程序。

尝试增加您的套接字的SO_SNDBUF选项。如果你想避免阻塞,它的值应大于bigest SendLength的值。 使用setsockopt()功能来改变SO_SNDBUF的值。