在web套接字上发送消息时,使用[encoding converto.]和chan-configure仍然感到困惑



前两天我就这个话题问了两个问题(一个可能合理,另一个很愚蠢(,但我似乎对这个话题仍然很感兴趣。我在SQLite中存储了一些文本,其中包括卷曲的撇号(U-2019&#8217(。查询结果存储在$result中,代码如下。这将发送到web套接字$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 [encoding convertto utf-8 "0 $id settle $result"]替换行set response "0 $id settle $result",则读取所有数据并呈现撇号。这解决了我的问题,但我认为我应该配置套接字,而不是编码$result

如果行未被替换,但chan configure $sock -encoding utf-8 -translation lf -eofchar {}被插入chan puts -nonewline $sock $response之前,则不会引发错误,并且撇号会出现,但不会读取所有数据,因此$response的一部分会丢失。我认为这是因为$len是在转换为utf-8之前确定的。

我的问题是:

  1. 在将字符串写入通道而不是编码$response之前,套接字是否应该配置为utf-8?如果是,在此之前如何确定正确的长度?为什么这比编码$reponse并保留通道二进制更可取?

  2. 如果信道应该配置为utf-8,如果在编码更改为utf-8之后,在信道被刷新以发送$response之后,在将其更改回二进制之前,偶然在信道上接收到新的传入消息,会发生什么?从实验来看,传入消息似乎无法在Tcl中读取,除非套接字是二进制的。

谢谢你对我的固执。

您似乎在使用websocket协议。这基本上是一个二进制协议。它使用位和字节来表示命令操作码、长度等。只有某些部分(文本框、关闭原因(包含utf-8字符串。即使是那些也需要以字节为单位给出长度。

至少对于发送二进制部分,通道需要配置为二进制。您可以临时将频道编码更改为utf-8以发送文本部分。但无论如何,您都需要使用encoding convertto utf-8命令来确定以字节为单位的长度。因此,以二进制模式发送已经转换的数据似乎比不断切换编码和发送原始字符串容易得多。但这两种方法都会奏效。

接收消息时,通道编码仅应用于您读取的数据。因此,您首先必须将通道设置为二进制,才能读取操作码和长度。即使后面跟着utf-8文本,您也只知道以字节为单位的长度,而不知道以字符为单位的。如果此时将通道编码更改为utf-8,则无法一次性读取字符串,因为您不知道要读取多少。所以你必须一个角色一个角色地去做。在二进制模式下,您只需读取指示的字节数,然后使用encoding convertfrom utf-8来获得所需的字符串。

显然,在类似websocket的协议中,使用二进制编码以及使用encoding命令对选定部分进行utf-8编码和解码要容易得多。

相关内容

最新更新