2009-07-17 34 views
2

我想限制我的應用程序發送速率爲900kbps,但問題是我使用的協議是消息導向的,並且消息的大小非常不同。我可以從40個字節一直到125000個字節的消息,並且所有消息都以原子單位發送。令牌桶或漏桶消息

我試過實現一個令牌桶緩衝區,但是如果我設置一個較低的桶大小,那麼大數據包永遠不會發送,而較大的桶會導致一個沒有速率限制的大型突發。

這是我用C小的實現:

typedef struct token_buffer { 
    size_t capacity; 
    size_t tokens; 
    double rate; 
    uint64_t timestamp; 

} token_buffer; 


static uint64_t time_now() 
{ 
    struct timeval ts; 
    gettimeofday(&ts, NULL); 
    return (uint64_t)(ts.tv_sec * 1000 + ts.tv_usec/1000); 
} 

static int token_buffer_init(token_buffer *tbf, size_t max_burst, double rate) 
{ 
    tbf->capacity = max_burst; 
    tbf->tokens = max_burst; 
    tbf->rate = rate; 
    tbf->timestamp = time_now(); 
} 

static size_t token_buffer_consume(token_buffer *tbf, size_t bytes) 
{ 
    // Update the tokens 
    uint64_t now = time_now(); 
    size_t delta = (size_t)(tbf->rate * (now - tbf->timestamp)); 
    tbf->tokens = (tbf->capacity < tbf->tokens+delta)?tbf->capacity:tbf->tokens+delta; 
    tbf->timestamp = now; 

    fprintf(stdout, "TOKENS %d bytes: %d\n", tbf->tokens, bytes); 

    if(bytes <= tbf->tokens) { 
    tbf->tokens -= bytes; 
    } else { 
    return -1; 
    } 

    return 0; 
} 

然後在某處的main():

while(1) { 
    len = read_msg(&msg, file); 

    // Loop until we have enough tokens. 
    // if len is larger than the bucket capacity the loop never ends. 
    // if the capacity is too large then no rate limit occurs. 
    while(token_buffer_consume(&tbf,msg, len) != 0) {} 

    send_to_net(&msg, len); 
} 

回答

2

你被max_burst限制最大郵件大小(被分配給tbf->容量) - 由於tbf->令牌永遠不會增加超過該值,因此檢查將永遠不會發送更大的消息:

if(bytes <= tbf->tokens) { 
    tbf->tokens -= bytes; 
    } else { 
    return -1; 
    } 

因此,代碼的確將突發限制爲max_burst--所以如果您希望突發大小,您應該對消息進行分段。

假設這是在代碼中唯一的地方,你可以插入限幅器,你可以,如果你更換了與上述片獲得更好的結果:

if(tbf->tokens > 0) { 
    tbf->tokens -= bytes; 
} else { 
    return -1; 
} 

語義會略有不同,但平均在很長的一段時間內,它應該會讓你大約是你正在尋找的速度。當然,如果您通過1gbps鏈路發送一條消息中的125K,則幾乎不可能談論900kbps的速率 - 它將是完整的1gbps突發數據包,並且在低速鏈路的情況下需要在某處排隊準備在這種情況下丟失一些數據包。

但是,根據您的應用和您使用的傳輸網絡協議(TCP/UDP/SCTP/...?),您可能需要將整形代碼向下移動 - 因爲網絡上的數據包通常是無論如何只有最多1500字節(包括各種網絡/傳輸協議頭文件)

有一點可能對測試有意思的事情是http://www.linuxfoundation.org/en/Net:Netem - 如果您的目標是試圖解決容量較小的鏈接。或者,抓住一對帶有1mbps串行端口的舊路由器。