You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决IO::Socket::Async UTF-8编码下末尾字符不输出问题?

解决IO::Socket::Async的UTF-8编码缓存问题

IO::Socket::Async的Supply在处理UTF-8编码时,会缓存可能与后续字节组合成完整Unicode字素的单字符(比如普通字母"a"),只有遇到明确的字素边界(如\n、空字节)时才会输出缓存内容,这就导致无边界的消息丢失最后一个字符。以下是几种针对性的解决方案:

方案1:使用内置的lines方法(推荐,适用于带换行符的文本协议)

如果你的协议以换行符作为消息终止符,直接用$connection.lines替代Supply即可,它会自动处理字素边界,确保完整输出每一行内容:

sub listen(Int $port) {
  react {
    whenever IO::Socket::Async.listen('0.0.0.0', $port) -> $connection {
      whenever $connection.lines -> $line {
        say $line;
        $connection.print: "$line\n";
      }
    }
  }
}

listen(9999);

方案2:手动维护缓冲区(适用于无固定终止符的场景)

自己维护一个字符串缓冲区,每次收到数据后提取所有完整的Unicode字素输出,剩余不完整的内容留在缓冲区;当连接关闭时,强制输出剩余缓存:

sub listen(Int $port) {
  react {
    whenever IO::Socket::Async.listen('0.0.0.0', $port) -> $connection {
      my $buffer = '';
      whenever $connection.Supply -> $chunk {
        $buffer ~= $chunk;
        # 提取所有完整的Unicode字素,留下不完整的内容在缓冲区
        while $buffer ~~ /^ (.*? \N) / {
          say $0;
          $connection.print: $0;
          $buffer = $buffer.substr($0.chars);
        }
      }
      # 连接关闭时输出剩余缓存
      whenever $connection.close-status {
        if $buffer {
          say $buffer;
          $connection.print: $buffer;
        }
      }
    }
  }
}

listen(9999);

其中\N用于匹配一个完整的Unicode字素,确保不会拆分需要组合的字符序列。

方案3:直接处理字节流(仅适用于确定无组合字符的场景)

如果你的场景中绝对不会出现Unicode组合字符,可以跳过IO::Socket::Async的字素处理逻辑,直接获取字节流并手动解码:

sub listen(Int $port) {
  react {
    whenever IO::Socket::Async.listen('0.0.0.0', $port) -> $connection {
      # 以字节模式获取数据流,手动解码为UTF-8
      whenever $connection.Supply(:bin) -> $bin_data {
        my $data = $bin_data.decode('utf-8');
        say $data;
        $connection.print: $data;
      }
    }
  }
}

listen(9999);

注意:这种方式如果遇到未完成的UTF-8字节序列,会抛出解码错误,仅适用于能保证所有数据都是完整UTF-8字节的场景。

关于你尝试用Channel加假\n无效的原因:IO::Socket::Async的字素缓存是在Supply底层处理的,后续追加\n无法触底底层缓存的输出,必须从Supply的处理逻辑本身入手解决。

内容的提问来源于stack exchange,提问作者Rawley Fowler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 05:20:43