2013-02-20 81 views
1

我有一個使用socket.io的服務器,我需要一種方法來限制發送服務器數據的客戶端太快。該服務器公開了一個TCP接口和一個socket.io接口 - 與TCP服務器(來自net模塊)我可以使用socket.pause()socket.resume(),這有效地節制了客戶端。但是使用socket.io的socket類沒有pause()resume()方法。Socket.IO服務器限制快速客戶端

什麼是最簡單的方式獲得反饋給客戶,它是壓倒性的服務器,需要放慢速度?我喜歡socket.pause()socket.resume(),因爲它不需要客戶端的任何附加代碼 - 備份TCP套接字,事情自然放慢。任何等效的socket.io?

更新:我提供了一個API來與服務器交互(目前有一個運行在TCP上的Python版本和一個使用socket.io的JavaScript版本)。所以我沒有任何真正的控制客戶端的功能。這就是爲什麼使用socket.pause()socket.resume()如此優秀 - 備份TCP流會減慢python客戶端的速度,無論它嘗試做什麼。我正在尋找一個JavaScript客戶端的等價物。

回答

3

隨着足夠的挖掘,我發現這個:

this.manager.transports[this.id].socket.pause(); 

this.manager.transports[this.id].socket.resume(); 

授予此如果socket.io連接不是網絡插座連接可能無法工作,並在以後的更新可能會中斷,但現在我會去它。當我在未來得到一些時間時,我可能會將它改爲Pascal提出的QUOTA_EXCEEDED解決方案。

+1

你會如何使用它?例如,在客戶端連接並且你有套接字之後,你把這個代碼放在哪裏? – Justin 2014-08-01 21:50:38

1

看起來你應該放慢你的客戶。如果一個客戶端發送速度太快以至於服務器無法跟上,那麼對於數百個客戶端來說,這並不會很好。

做到這一點的一種方法是讓客戶等待每個發射的迴應,然後再發射其他東西。通過這種方式,服務器可以通過僅在準備就緒時回答客戶端可以發送的速度,或者僅在設定的時間後回答。

如果這還不夠,當客戶端每秒超出x次請求時,開始回覆類似QUOTA_EXCEEDED錯誤的錯誤,並忽略它們發送的數據。這將迫使外部開發人員讓他們的應用按照您的需要行事做。

+0

不幸的是,我只是提供一個API來與服務器交互;我無法直接控制客戶的工作方式。這就是爲什麼'socket.pause()'如此完美 - 客戶端無法繞過TCP流的阻塞。 – Zik 2013-02-21 03:57:42

+0

那麼,如果客戶端開始發送太多的請求,就像QUOTA_EXCEEDED一樣發回一個錯誤。這是很多API所做的。這應該引起客戶的注意,也是它的開發者。試着明確客戶是否超出每分鐘配額或每日配額。 – 2013-02-21 07:33:41

0

如果您對您的服務器的某個地方的回調通常發回給你的客戶端的響應,你可以嘗試改變它像這樣:

前:

var respond = function (res, callback) { 
    res.send(data); 
    }; 

var respond = function (res, callback) { 
    setTimeout(function(){ 
     res.send(data); 
     }, 500); // or whatever delay you want. 
    }; 
+0

對所有消息都有響應,但客戶端在發送更多數據之前不必等待響應。客戶端不是由我寫的,所以我無法控制它的工作方式。 – Zik 2013-02-21 03:56:05

+0

我明白了。這是您想要調節的傳入請求。我想你需要查看socket.io代碼,看看你是否可以訪問套接字(這將在某處)。好挑戰! (我同意做服務器端是最好的) – AndyD 2013-02-21 10:37:55

0

至於另一項建議,我會提出這樣一個解決方案: 是很常見的MySQL來得到大量的請求這將需要更長的時間比要求在未來的利率申請 服務器可以記錄請求數據庫中的一個表中,假設此操作對於請求進入的速率足夠快,然後以正常速率處理隊列以供服務器維持。此緩衝區系統將允許服務器運行緩慢但仍處理所有請求。

但是,如果你想要順序的東西,那麼請求回調應該在客戶端可以發送另一個請求之前進行驗證。在這種情況下,應該有一個服務器就緒標誌。如果客戶端在標誌仍爲紅色時發送請求,則可能會有消息告訴客戶端速度變慢。

0

這是一個骯髒的方法來實現節流。雖然這是一箇舊帖子,有些人可能會從中受益:

首先註冊一箇中間件:

io.on("connection", function (socket) { 

socket.use(function (packet, next) { 
    if (throttler.canBeServed(socket, packet)) { 
     next(); 
    } 
}); 
//You other code .. 
}); 

canBeServed是一個簡單的調節器,如下圖所示:

function canBeServed(socket, packet) { 
if (socket.markedForDisconnect) { 
    return false; 
} 

var previous = socket.lastAccess; 
var now = Date.now(); 
if (previous) { 
    var diff = now - previous; 

    //Check diff and disconnect if needed. 
    if (diff < 50) { 
     socket.markedForDisconnect = true; 
     setTimeout(function() { 
      socket.disconnect(true); 
     }, 1000); 
     return false; 
    } 
} 

socket.lastAccess = now; 

return true; 
} 

您可以使用process.hrtime()代替日期。時間()。