1

データを待機バッファーに格納する必要がある場合 (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 に感謝)
4

1 に答える 1

0

while ループの先頭では、既に が減分されnLeftているため、減算する必要はありませんnPosition

iResult = send(m_Socket, (char*)(buf + nPosition), nLeft, 0);

2 番目の関数で、未送信のバイトを配列の先頭にシフトする場合は、memmove領域が重複しているため (領域m_SendBufferをそれ自体にコピーしているため)、 を使用する必要があります。オーバーラップを以下に示します。ここでは、Aの一部がそれ自体にコピーされます。

m_SendBuffer: [XXXXAAAAAAAAAAAA]
mPosition: 4
nLeft: 12

DataSend()が発生した場合でも、発信者が呼び出しを成功させ続けることができるようにするために が実装されている理由について、少し混乱していWSAEWOULDBLOCKます。送信を停止する必要があることを発信者に知らせる結果を返し、送信を再開する指示を待つようにインターフェイスを変更することをお勧めします。

nPosition > 0チェックは必要ありません。

データの受信者が何も読み取らないようにすることで、ケースを強制的に発生させることができます。

sendノンブロッキング モードでは、要求されたよりも少ないバイトを送信する可能性があります。

于 2012-06-10T23:09:04.407 に答える