2009-06-25 129 views
0

我已經實現了一個簡單的套接字包裝類。它包括一個無阻塞功能:加速非阻塞Unix套接字(C++)

void Socket::set_non_blocking(const bool b) { 
    mNonBlocking = b; // class member for reference elsewhere 
    int opts = fcntl(m_sock, F_GETFL); 
    if(opts < 0) return; 
    if(b) 
     opts |= O_NONBLOCK; 
    else 
     opts &= ~O_NONBLOCK; 

    fcntl(m_sock, F_SETFL, opts); 
} 

該類還包含一個簡單的接收功能:

int Socket::recv(std::string& s) const { 
    char buffer[MAXRECV + 1]; 
    s = ""; 
    memset(buffer,0,MAXRECV+1); 
    int status = ::recv(m_sock, buffer, MAXRECV,0); 

    if(status == -1) { 
    if(!mNonBlocking) 
     std::cout << "Socket, error receiving data\n"; 

     return 0; 
    } else if (status == 0) { 
     return 0; 
    } else { 
     s = buffer; 
     return status; 
    } 
} 

在實踐中,似乎有一個〜15ms的延遲時插槽::的recv()是調用。這個延遲是否可以避免?我見過一些使用select()的非阻塞示例,但不明白這可能會有幫助。

回答

1

這取決於你如何使用套接字。如果您有多個套接字,並且您在所有這些套接字上循環檢查可能導致延遲的數據。

對於非阻塞recv,您取決於存在的數據。如果您的應用程序需要使用多個套接字,則必須輪流連接每個套接字以查找其中是否有任何數據可用。

這對系統資源不利,因爲這意味着即使沒有任何事情可做,您的應用程序也會持續運行。

你可以通過select來避免這種情況。你基本上設置你的套接字,將它們添加到組中並在組上選擇。當任何選定的套接字發生任何事情時,選擇返回指定發生了什麼以及在哪個套接字上。

有關如何使用select看看beej's guide to network programming

+0

謝謝你的建議,但我的問題認爲字面上只有1個套接字,其中recv()的調用呈現不可接受的15毫秒延遲。既然它只是輪詢1個套接字,我猜猜問題在別處是不正確的嗎? – duckworthd 2009-06-25 03:23:04

+0

可能還有其他因素,根據少量代碼無法判斷髮生了什麼。如果只有一個套接字,並且我假設您正在等待數據,爲什麼您要使用非阻塞?這是否意味着您在等待數據時正在做其他事情?其他工作是否有可能讓您一收到數據就馬上收到數據? – stefanB 2009-06-25 03:37:05

0

選擇會讓你指定超時,並且可以測試插座已經可以讀出一些代碼。所以你可以使用小於15ms的東西。順便提一句,如果線路上的數據可以包含嵌入式NUL,則不必包含所有讀取的數據,您需要注意您擁有的代碼。你應該使用類似s.assign(buffer, status);

0

除了stefanB,我發現你每次都清零你的緩衝區。何必? recv返回實際讀取的字節數。 (緩衝區[狀態+ 1] = NULL後只需將一個字節清零)

0

MAXRECV有多大?這可能就是因爲堆棧增長而導致頁面錯誤。其他人已經提到,清零接收緩衝區是完全沒有必要的。當您從收到的字符數據中創建std::string時,您還可以進行內存分配和複製匹配。