1. 程式人生 > >網路程式設計:send/write強制傳送所有資料

網路程式設計:send/write強制傳送所有資料

send通過socket傳送資料的時候,不能保證傳送的資料在網路傳輸過程中,能一次傳輸到接收端。

send傳送的資料,只是將應用層資料傳送給kernel的緩衝區,而kernel緩衝區接收到應用層的資料之後,會根據當前自身的狀態來確定如何傳送接收的資料。具體業務邏輯,見<>

而此處想強調的是,將send傳送的所有資料強制發給kernel緩衝區之後,才繼續下一步的操作。

非常簡單的業務需求

程式碼實現:

0)設定一個標記 nTotalLength,記錄send成功傳送資料的長度

1)開啟一個for迴圈(while也可以)

2)設定迴圈傳送的最大次數

3)呼叫send傳送你想傳送的全部資料 nLength

4)跟蹤傳送到kernel緩衝區的資料大小

5)判斷髮送返回值:如果斷開連線或出錯,則停止傳送,並記錄當前錯誤資訊

6)如果條件5)正常,則更新標記 nTotalLength

7)判斷資料是否傳送完畢,nTotalLength和 nLength相等,退出迴圈,否則,繼續傳送

c/c++ code:

HRESULT SendTotal(SOCKET sock, PCHAR pszSend, int nLength, int *pnActualLength)
{
    TRACE_FN_SCOPE;

    HRESULT hResult = E_FAIL;

    int nTotalLength = 0, nSentLength = 0;

    TRACE(INFO, L"Send Data Length:%d", nLength);
    //forces to send all bytes until error or socket shutdown

    for (int nLoopCount = 0; ; nLoopCount++)
    {
        if (nLoopCount > MAX_LOOP_COUNT)
            ERROR_ESCAPE(TRUE, E_FAIL, L"Too many loops");

        TRACE(INFO, L"Intended send length; %d", nLength - nTotalLength);
        nSentLength = send(sock, pszSend + nTotalLength, nLength - nTotalLength, 0);
        TRACE(INFO, L"Sent length: %d", nSentLength);
        ERROR_ESCAPE(nSentLength == 0 || nSentLength == SOCKET_ERROR, 
            ::WSAGetLastError() ? ::WSAGetLastError() : E_FAIL, L"Check send length");

        nTotalLength += nSentLength;

        if(nTotalLength == nLength)
            break;
    }

    hResult = S_OK;

_err:
    if (pnActualLength != NULL)
        *pnActualLength = nTotalLength;
    TRACE(INFO, L"Total sent length: %d/%d", nTotalLength, nLength);

    return hResult;
}

---end---