Skip to content

Commit 540695f

Browse files
committed
Reworked _runQueue to prioritize control frames
1 parent 9ffe46f commit 540695f

1 file changed

Lines changed: 38 additions & 17 deletions

File tree

src/AsyncWebSocket.cpp

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -372,26 +372,47 @@ void AsyncWebSocketClient::_runQueue() {
372372

373373
_clearQueue();
374374

375-
if (!_controlQueue.empty() && !_controlQueue.front().finished() && (_messageQueue.empty() || _messageQueue.front().betweenFrames())
376-
&& webSocketSendFrameWindow(_client) > (size_t)(_controlQueue.front().len() - 1)) {
377-
_controlQueue.front().send(_client);
378-
}
379-
380-
if (webSocketSendFrameWindow(_client)) {
381-
for (auto &msg : _messageQueue) {
382-
if (msg._remainingBytesToSend()) {
383-
msg.send(_client);
375+
size_t space = webSocketSendFrameWindow(_client);
376+
377+
if (space) {
378+
// control frames have priority over message frames
379+
// we can send a control frame if:
380+
// - there is no message frame in the queue, or the first message frame is between frames (all bytes sent are acked)
381+
// - the control frame is not finished (not sent yet)
382+
// - there is enough space to send the control frame (control frames are small, at most 129 bytes, so we can assume that if there is space to send it, it can be sent in one go)
383+
if (_messageQueue.empty() || _messageQueue.front().betweenFrames()) {
384+
for (auto &ctrl : _controlQueue) {
385+
if (ctrl.finished()) {
386+
continue;
387+
}
388+
if (space > (size_t)(ctrl.len() - 1)) {
389+
async_ws_log_v("WS[%" PRIu32 "] Sending control frame: %" PRIu8 ", len: %" PRIu8, _clientId, ctrl.opcode(), ctrl.len());
390+
ctrl.send(_client);
391+
space = webSocketSendFrameWindow(_client);
392+
}
384393
}
394+
}
385395

386-
// If we haven't finished sending this message, we must stop here to preserve WebSocket ordering.
387-
// We can only pipeline subsequent messages if the current one is fully passed to TCP buffer.
388-
if (msg._remainingBytesToSend()) {
389-
break;
390-
}
396+
// then we can send message frames if there is space
397+
if (space) {
398+
for (auto &msg : _messageQueue) {
399+
if (msg._remainingBytesToSend()) {
400+
async_ws_log_v("WS[%" PRIu32 "] Send message fragment: %u/%u, acked: %u/%u", _clientId, msg._remainingBytesToSend(), msg._sent + msg._remainingBytesToSend(), msg._acked, msg._ack);
401+
// will use all the remaining space, or all the remaining bytes to send, whichever is smaller
402+
msg.send(_client);
403+
space = webSocketSendFrameWindow(_client);
404+
405+
// If we haven't finished sending this message, we must stop here to preserve WebSocket ordering.
406+
// We can only pipeline subsequent messages if the current one is fully passed to TCP buffer.
407+
if (msg._remainingBytesToSend()) {
408+
break;
409+
}
410+
}
391411

392-
// not enough space for another message
393-
if (!webSocketSendFrameWindow(_client)) {
394-
return;
412+
// not enough space for another message
413+
if (!space) {
414+
break;
415+
}
395416
}
396417
}
397418
}

0 commit comments

Comments
 (0)