前两天我就这个主题问了两个问题(one可能是合理的,而other相当愚蠢),但我似乎仍然在这个主题上相当密集。(U-2019 ’).查询的结果存储在$result
中,如下面的代码所示。它被发送到Web Socket $sock
上的浏览器。
这段代码会导致浏览器阅读所有数据,而不会在Tcl或浏览器中抛出错误,但不会呈现弯曲的撇号。
chan configure $sock -buffering full -blocking 0 -translation binary
set response "0 $id settle $result"
# set response [encoding convertto utf-8 "0 $id settle $result"]
set len [string length $response]
if { $len > 65535 } {
chan puts -nonewline $sock [binary format cu2Wu {129 127} $len]
} elseif { $len > 125 } {
chan puts -nonewline $sock [binary format cu2Su {129 126} $len]
} elseif { $len > 0 } {
chan puts -nonewline $sock [binary format cu2 [list 129 $len]]
}
# chan configure $sock -encoding utf-8 -translation lf -eofchar {}
chan puts -nonewline $sock $response
chan flush $sock
chan configure $sock -buffering full -blocking 0 -translation binary
如果将set response "0 $id settle $result"
行替换为set response [encoding convertto utf-8 "0 $id settle $result"]
,则会读取所有数据并呈现撇号。这解决了我的问题,但我认为我应该配置套接字,而不是编码$result
。
如果没有替换该行,而是在chan puts -nonewline $sock $response
之前插入了chan configure $sock -encoding utf-8 -translation lf -eofchar {}
,则不会抛出错误,并且会呈现撇号,但不会读取所有数据,从而丢失了$response
的一部分。我认为这是因为$len
在转换为utf-8之前就已确定。
我的问题是:
1.在将字符串写入通道之前,套接字是否应该配置为utf-8,而不是编码$response
?如果是,在此之前如何确定正确的长度?为什么这比编码$reponse
和保留通道二进制更可取?
1.如果通道应该配置为utf-8,那么如果在编码更改为utf-8之后,并且在刷新通道以发送$response
之后将其更改回二进制之前,在通道上偶然接收到新的传入消息,会发生什么情况?从实验中可以看出,除非套接字是二进制,否则传入消息无法在Tcl中读取。
谢谢你容忍我的愚蠢。
1条答案
按热度按时间zqdjd7g91#
你似乎正在使用WebSocket协议。这基本上是一个二进制协议。它使用位和字节来表示命令的操作码、长度等。只有一些部分(文本帧、关闭原因)包含utf-8字符串。即使是那些部分也需要以字节为单位给出长度。
至少为了发送二进制部分,通道需要配置为二进制。您可以暂时将通道编码更改为utf-8来发送文本部分。但无论如何,您需要使用
encoding convertto utf-8
命令来确定以字节为单位的长度。因此,以二进制模式发送已转换的数据似乎比不断切换编码并发送原始字符串要容易得多。但这两种方法都行得通。当接收消息时,通道编码只应用于您读取的数据。因此,您必须首先将通道设置为二进制以读取操作码和长度。即使后面是utf-8文本,您也只知道以字节为单位的长度,而不是以字符为单位的长度。如果此时将通道编码更改为utf-8,你不能一次读完这个字符串,因为你不知道要读多少。所以你必须一个字符一个字符地读。在二进制模式下,你可以只读指定的字节数,然后使用
encoding convertfrom utf-8
来得到你想要的字符串。显然,在WebSocket这样的协议中,使用二进制编码和使用
encoding
命令对选定部分进行utf-8编码和解码要容易得多。