QtWebEngine使用IPC机制在C + Qt世界和JavaScript工作之间进行通信。此机制用于QWebChannel,它似乎基于WebSockets。有没有办法在不使用QWebChannel的情况下使用底层IPC或WebSockets,因为后者似乎仅限于字符串或JSON编码数据?
背景:我编写了一个应用程序QtDomTerm,它是一个基于JavaScript的终端模拟器,它使用QWebChannel将来自PTY的输入/输出连接到QtWebEngine。这工作得相当好,但是有一个与utf8 /字符串转换有关的故障。理想情况下,我想从PTY发送原始字节,并在JavaScript中进行字节到文本的转换。但是QWebChannel太高级,只处理字符串或JSON编码的数据。它不处理QByteArray。
当然有多种方法可以解决我的问题。一种是手动创建WebSocket服务器,并让QtWebEngine中运行的JavaScript连接到它。但似乎无论如何,使用qt.webChannelTransport
是幕后发生的事情。如果我可以访问底层传输(类WebChannelIPCTransportHost
似乎是相关的),它似乎是最有效和优雅的。
有人试过这样的事吗?即我想不使用QWebChannel - 除非有一种有效的方式来传递QByteArray。
(我改写了这个问题。有关于缺少研究的评论,但我通过Qt docuemntation,源代码以及此处没有找到明确的答案而大量浏览。)
答案 0 :(得分:1)
什么阻止您发送QString::fromLatin1(data.toHex())
,其中data
属于QByteArray
类型?真的,这就是你所需要的一切。在javascript端使用反向转换,请参阅例如this question
答案 1 :(得分:1)
因为似乎不是一种方法,所以"低于" 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;
}
是的,这太过分了,而且几乎肯定是过早的优化,但我无法帮助自己: - )