Perl 的 Websocket 服务器时,如果我使用 send_utf8 发送长度超过 16,000 个字符的 json 消息,它会导致在 Chrome 中与 websocket 的连接被终止,并显示以下消息:
"无法将文本框架解码为 UTF-8"。
此Websocket 服务器可以发送的消息长度是否有一些限制,有没有办法绕过此限制?
它失败是因为(截至 0.001003( Net::WebSocket::Server::Connection 初始化其协议::WebSocket::Frame 对象,而不设置覆盖 65535 字节限制的"max_payload_size"。如果模块作者更新这些调用以允许更大的缓冲区或更好的缓冲区传递用户定义的值,则可以轻松解决此问题。
显然,可以在Protocol::WebSocket::Frame构造函数(https://github.com/vti/protocol-websocket/issues/24#issuecomment-27095561(中设置有效负载大小。
不幸的是,cpan 上的文档似乎缺少这些信息。
试试这个:
$hs->build_frame(buffer => $my_data, max_payload_size => 200000)->to_bytes);
我认为传出消息的大小实际上不是问题。我有同样的确切问题,将"max_payload_size"设置为更大的值并不能解决它。如果这是问题所在,您将看到来自 Frame.pm"to_bytes"子"有效载荷太大"的错误消息。发送更短的消息或增加max_payload_size"。当我通过 16k 从服务器向 Chrome 发送消息时,我在服务器上没有看到此错误(或任何其他错误(,是的,我仍然收到"无法将文本框架解码为 UTF-8",其中"(操作码 -1("作为框架消息正文在 Chrome 检查器网络选项卡中以红色突出显示。
我认为这更有可能是IO::Socket::SSL问题,因为我正在按照Net::WebSocket::Server文档中的规定使用它。我很好奇你是否很好,或者你是否在常规的未加密套接字中看到这个问题。
从 IO::套接字::SSL 文档:
syswrite( BUF, [ LEN, [ OFFSET ]] ( 此函数的行为来自 与其他 IO::Socket 对象中的系统写入相同,例如它将 最多写入 LEN 字节到套接字,但不能保证 写入所有 LEN 字节。它将返回写入的字节数。 syswrite将在单个SSL帧中写入所有数据,该帧 意味着不超过 16,384 字节,这是 SSL框架,可以一次写入。
Net::WebSocket::Server::Connection 在构建框架后调用 syswrite:
syswrite($self->{socket}, $bytes);
我很好奇如何处理这个问题的任何想法。也许 Frame 模块在使用 SSL 时应该对低于 16k 的消息进行分段,但我认为这必须以 Connection.pm 处理。
使用解决方案更新:
事实证明,如果您愿意修改 Connection.pm 并将系统写入放入 16K 循环中,这是一个非常简单的修复。请记住,SSL 框架和 WebSocket 框架不是一回事,我们只需要不要溢出 SSL 帧大小。请参阅工作解决方案:
sub send {
my ($self, $type, $data) = @_;
if ($self->{handshake}) {
carp "tried to send data before finishing handshake";
return 0;
}
my $frame = new Protocol::WebSocket::Frame(type => $type, max_payload_size => $self->{max_send_size});
$frame->append($data) if defined $data;
my $bytes = eval { $frame->to_bytes };
if (!defined $bytes) {
carp "error while building message: $@" if $@;
return;
}
# modified to not overflow the 16k SSL frame size
while( 16384 < length $bytes ) {
syswrite( $self->{socket}, $bytes, 16384 );
substr( $bytes, 0, 16384, '' );
}
syswrite($self->{socket}, $bytes);
}
我能够将一个 27k 的 json 字符串发送回 Chrome,该字符串以前无法通过 SSL 工作。