我对何时需要将数据存储在等待缓冲区中(等待FD_WRITE事件)有一些疑问。
这是我的发送函数(固定):
bool MyClass::DataSend(char *buf, int len)
{
if (len <=0 || m_Socket == INVALID_SOCKET) return false;
if (m_SendBufferLen > 0)
{
if ((m_SendBufferLen + len) < MAX_BUFF_SIZE)
{
memcpy((m_SendBuffer + m_SendBufferLen), buf, len);
m_SendBufferLen += len;
return true;
}
else
{
// close the connection and log insuficient wait buffer size
return false;
}
}
int iResult;
int nPosition = 0;
int nLeft = len;
while (true)
{
iResult = send(m_Socket, (char*)(buf + nPosition), nLeft, 0);
if (iResult != SOCKET_ERROR)
{
if (iResult > 0)
{
nPosition += iResult;
nLeft -= iResult;
}
else
{
// log 0 bytes sent
break;
}
}
else
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
if ((m_SendBufferLen + nLeft) < MAX_BUFF_SIZE)
{
// log data copied to the wait buffer
memcpy((m_SendBuffer + m_SendBufferLen), (buf + nPosition), nLeft);
m_SendBufferLen += nLeft;
return true;
}
else
{
// close the connection and log insuficient wait buffer size
return false;
}
}
else
{
// close the connection and log winsock error
return false;
}
}
if (nLeft <= 0) break;
}
return true;
}
我的发送(FD_WRITE事件)功能(已修复):
bool MyClass::DataSendEvent()
{
if (m_SendBufferLen < 1) return true;
int iResult;
int nPosition = 0;
int nLeft = m_SendBufferLen;
while (true)
{
iResult = send(m_Socket, (char*)(m_SendBuffer + nPosition), nLeft, 0);
if (iResult != SOCKET_ERROR)
{
if (iResult > 0)
{
nPosition += iResult;
nLeft -= iResult;
}
else
{
// log 0 bytes sent
break;
}
}
else
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
if (nPosition > 0)
{
memmove(m_SendBuffer, (m_SendBuffer + nPosition), (m_SendBufferLen - nPosition));
m_SendBufferLen -= nPosition;
}
break;
}
else
{
// close the connection and log winsock error
return false;
}
}
if (nLeft <= 0)
{
if (m_SendBufferLen == nPosition)
{
m_SendBufferLen = 0;
break;
}
else
{
memmove(m_SendBuffer, (m_SendBuffer + nPosition), (m_SendBufferLen - nPosition));
m_SendBufferLen -= nPosition;
nPosition = 0;
nLeft = m_SendBufferLen;
}
}
}
return true;
}
我真的需要if (nPosition > 0)
吗?如何模拟此场景?在非阻塞模式下,是否有可能 send() 发送的字节数少于请求的字节数?如果没有,为什么要使用 while() 循环?
- 这是最终代码(感谢@user315052)
在 while 循环的顶部,您已经在递减nLeft
,因此您无需从中减去nPosition
。
iResult = send(m_Socket, (char*)(buf + nPosition), nLeft, 0);
在第二个函数中,当您将未发送的字节移动到数组的开头时,您应该使用 memmove
,因为您有重叠的区域(您正在将 m_SendBuffer
的区域复制到自身中)。重叠如下所示,其中一些A
将被复制到自身上。
m_SendBuffer: [XXXXAAAAAAAAAAAA]
mPosition: 4
nLeft: 12
我对为什么实施DataSend()
以允许调用者即使在遇到WSAEWOULDBLOCK
时也能成功调用它感到有些困惑。我建议修改接口以返回一个结果,让调用者知道它应该停止发送,并等待指示恢复发送。
您不需要nPosition > 0
检查。
您可以通过让数据接收方不读取任何内容来强制发生这种情况。
处于非阻塞模式的send
发送的字节数绝对有可能少于请求的字节数。