Perl Websocket服务器导致;无法将文本帧解码为UTF-8“;含铬

Perl Websocket服务器导致;无法将文本帧解码为UTF-8“;含铬,perl,websocket,Perl,Websocket,使用Perl时,如果我使用send_utf8发送一条长度超过16000个字符的json消息,则会导致在Chrome中终止与websocket的连接,并显示以下消息: “无法将文本帧解码为UTF-8” 此Websocket服务器可以发送的消息长度是否有限制,是否有办法绕过此限制?它失败,因为(从0.001003起)Net::Websocket::server::Connection在未设置“最大有效负载大小”的情况下初始化其协议::Websocket::Frame对象它覆盖了65535字节的限制。

使用Perl时,如果我使用send_utf8发送一条长度超过16000个字符的json消息,则会导致在Chrome中终止与websocket的连接,并显示以下消息:

“无法将文本帧解码为UTF-8”


此Websocket服务器可以发送的消息长度是否有限制,是否有办法绕过此限制?

它失败,因为(从0.001003起)Net::Websocket::server::Connection在未设置“最大有效负载大小”的情况下初始化其协议::Websocket::Frame对象它覆盖了65535字节的限制。如果模块作者更新这些调用以允许更大的缓冲区或更好的缓冲区通过用户定义的值,则问题可以轻松解决。

显然,可以在Protocol::WebSocket::Frame构造函数()中设置有效负载大小

不幸的是,cpan上的文档似乎缺少这些信息

试试这个:

$hs->build_frame(buffer => $my_data, max_payload_size => 200000)->to_bytes);

我认为发送消息的大小实际上不是问题所在。我也有同样的问题,将“max_payload_size”设置为更大的值并不能解决这个问题。如果这是问题所在,您将看到Frame.pm“to_bytes”sub“有效负载太大”的错误消息。请发送较短的消息或增加最大有效负载大小”。当我通过16k从服务器向Chrome发送消息时,我在服务器上没有看到此错误(或任何其他错误),是的,我仍然得到“无法将文本帧解码为UTF-8”,并在Chrome inspector网络选项卡中以红色突出显示帧消息体(操作码-1)”

我认为这更可能是一个IO::Socket::SSL问题,因为我是按照Net::WebSocket::Server文档中的规定使用它的。我很好奇您是否健康,或者您是否在常规的未加密套接字中看到此问题

从IO::Socket::SSL文档:

syswrite(BUF、[LEN、[OFFSET]])此函数从 与其他IO::Socket对象中的syswrite相同,例如 最多向套接字写入LEN字节,但不能保证 所有LEN字节都被写入。它将返回写入的字节数。 syswrite将在单个SSL帧中写入所有数据,这 表示不超过16384字节,这是一个 SSL帧,可以一次写入

Net::WebSocket::Server::Connection正在生成框架后调用syswrite:

syswrite($self->{socket}, $bytes);
我想知道如何处理这个问题。当使用SSL时,框架模块可能应该将16k以下的消息分段,但我认为这必须在Connection.pm中处理

更新了解决方案:

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);
}
如果您愿意修改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);
}
子发送{
我的($self,$type,$data)=@;
如果($self->{handshake}){
carp“试图在握手结束前发送数据”;
返回0;
}
my$frame=newprotocol::WebSocket::frame(type=>$type,max\u payload\u size=>$self->{max\u send\u size});
$frame->append($data)(如果定义了$data);
my$bytes=eval{$frame->to_bytes};
如果(!定义的$bytes){
如果$@,则为“生成消息时出错:$@”;
返回;
}
#修改为不溢出16k SSL帧大小
而(16384<长度$字节){
syswrite($self->{socket},$bytes,16384);
substr($bytes,016384,');
}
syswrite($self->{socket},$bytes);
}

我能够将一个27k json字符串发送回以前未通过SSL工作的Chrome。

我给该库的作者发了电子邮件,他写道:“底层协议::WebSocket::Frame模块施加的限制似乎是65535字节”。我认为这是相关的,我达到的16000个字符的限制可能是因为send_utf8将每个字符视为4个字节。不过,我希望得到一个更明确的答案,以及一个可能的解决办法。