Skip to content

Commit a3a1466

Browse files
committed
Reworked _runQueue to prioritize control frames
1 parent 7f17723 commit a3a1466

1 file changed

Lines changed: 41 additions & 17 deletions

File tree

src/AsyncWebSocket.cpp

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -372,26 +372,50 @@ 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(
401+
"WS[%" PRIu32 "] Send message fragment: %u/%u, acked: %u/%u", _clientId, msg._remainingBytesToSend(), msg._sent + msg._remainingBytesToSend(),
402+
msg._acked, msg._ack
403+
);
404+
// will use all the remaining space, or all the remaining bytes to send, whichever is smaller
405+
msg.send(_client);
406+
space = webSocketSendFrameWindow(_client);
407+
408+
// If we haven't finished sending this message, we must stop here to preserve WebSocket ordering.
409+
// We can only pipeline subsequent messages if the current one is fully passed to TCP buffer.
410+
if (msg._remainingBytesToSend()) {
411+
break;
412+
}
413+
}
391414

392-
// not enough space for another message
393-
if (!webSocketSendFrameWindow(_client)) {
394-
return;
415+
// not enough space for another message
416+
if (!space) {
417+
break;
418+
}
395419
}
396420
}
397421
}

0 commit comments

Comments
 (0)