因爲似乎沒有要很長的路要走「下面」的QWebChannel(沒有黑客的Qt本身)似乎有三種選擇:
創建一個單獨的WebSockets連接。這需要更大的非本地更改,並可能會創建額外的流程。
在C++端執行字節到文本解碼,也許使用QTextDecoder。這可能是最簡單的。但是,有一些體系結構的原因讓我們更喜歡在接近我們做轉義序列處理的地方進行文本解碼。這當然更傳統,並可能更好地處理角落案件。另外DomTerm需要與QtDomTerm前端的其他前端一起工作。
將字節流編碼爲一串字符串,使用QWebChannel傳輸後者,在JavaScript端轉換回字節,然後在JavaScript中處理文本解碼。
我選擇實施第三個選項。在轉換後端的方面有一些開銷。不過,我設計和實現的編碼是相當有效率:
/** Encode an arbitrary sequence of bytes as an ASCII string.
* This is used because QWebChannel doesn't have a way to transmit
* data except as strings or JSON-encoded strings.
* We restrict the encoding to ASCII (i.e. codes less then 128)
* to avoid excess bytes if the result is UTF-8-encoded.
*
* The encoding optimizes UTF-8 data, with the following byte values:
* 0-3: 1st byte of a 2-byte sequence encoding an arbitrary 8-bit byte.
* 4-7: 1st byte of a 2-byte sequence encoding a 2-byte UTF8 Latin-1 character.
* 8-13: mean the same ASCII control character
* 14: special case for ESC
* 15: followed by 2 more bytes encodes a 2-byte UTF8 sequence.
* bytes 16-31: 1st byte of a 3-byte sequence encoding a 3-byte UTF8 sequence.
* 32-127: mean the same ASCII printable character
* The only times we generate extra bytes for a valid UTF8 sequence
* if for code-points 0-7, 14-26, 28-31, 0x100-0x7ff.
* A byte that is not part of a valid UTF9 sequence may need 2 bytes.
* (A character whose encoding is partial, may also need extra bytes.)
*/
static QString encodeAsAscii(const char * buf, int len)
{
QString str;
const unsigned char *ptr = (const unsigned char *) buf;
const unsigned char *end = ptr + len;
while (ptr < end) {
unsigned char ch = *ptr++;
if (ch >= 32 || (ch >= 8 && ch <= 13)) {
// Characters in the printable ascii range plus "standard C"
// control characters are encoded as-is
str.append(QChar(ch));
} else if (ch == 27) {
// Special case for ESC, encoded as '\016'
str.append(QChar(14));
} else if ((ch & 0xD0) == 0xC0 && end - ptr >= 1
&& (ptr[0] & 0xC0) == 0x80) {
// Optimization of 2-byte UTF-8 sequence
if ((ch & 0x1C) == 0) {
// If Latin-1 encode 110000aa,10bbbbbb as 1aa,0BBBBBBB
// where BBBBBBB=48+bbbbbb
str.append(4 + QChar(ch & 3));
} else {
// Else encode 110aaaaa,10bbbbbb as '\017',00AAAAA,0BBBBBBB
// where AAAAAA=48+aaaaa;BBBBBBB=48+bbbbbb
str.append(QChar(15));
str.append(QChar(48 + (ch & 0x3F)));
}
str.append(QChar(48 + (*ptr++ & 0x3F)));
} else if ((ch & 0xF0) == 0xE0 && end - ptr >= 2
&& (ptr[0] & 0xC0) == 0x80 && (ptr[1] & 0xC0) == 0x80) {
// Optimization of 3-byte UTF-8 sequence
// encode 1110aaaa,10bbbbbb,10cccccc as AAAA,0BBBBBBB,0CCCCCCC
// where AAAA=16+aaaa;BBBBBBB=48+bbbbbb;CCCCCCC=48+cccccc
str.append(QChar(16 + (ch & 0xF)));
str.append(QChar(48 + (*ptr++ & 0x3F)));
str.append(QChar(48 + (*ptr++ & 0x3F)));
} else {
// The fall-back case - use 2 bytes for 1:
// encode aabbbbbb as 000000aa,0BBBBBBB, where BBBBBBB=48+bbbbbb
str.append(QChar((ch >> 6) & 3));
str.append(QChar(48 + (ch & 0x3F)));
}
}
return str;
}
是的,這是矯枉過正,幾乎可以肯定過早的優化,但我不能幫助自己:-)
是的,這是肯定是可行的(並且相對簡單)將字節轉換爲十六進制,並傳輸結果字符串。但它無可否認效率低下,因爲它將傳輸的數據量加倍。它也冒犯了我的優雅感:爲什麼要將字節轉換爲十六進制 - 無論如何,當我們使用字節協議時。在我的應用程序中,我確實不需要QWebChanell的功能 - 我只需要一個簡單的雙向字節通道,因爲我已經有了一種「帶外」消息機制。 –
你不能使用普通的TCP套接字和websockets嗎? –
使用「TCP套接字和websockets」很好(實質上是我想做的) - 但不是創建一個新的監聽器和連接,我認爲在現有的IPC連接上更簡單,更強大。 (例如,並非所有環境都可以訪問TCP套接字。)QWebChannel已經建立了一個連接;我只想在低(字節流)級別使用現有連接,而不是較高的QWebChannel級別。 (我更新了這個問題,希望更清楚一點。) –