Perl客户端到Java服务器

Perl客户端到Java服务器,java,perl,Java,Perl,我试图编写一个perl客户端程序来连接Java服务器应用程序(JDuplicate)。我看到java服务器使用DataInput.readUTF和DataInput.writeUTF方法,JDuplicate网站将其列为“java修改的UTF-8协议” 我的测试程序非常简单,我正在尝试发送客户端类型的数据,这应该会调用服务器的响应,但它只是超时: #!/usr/bin/perl use strict; use Encode; use IO::Socket; my $remote = IO::

我试图编写一个perl客户端程序来连接Java服务器应用程序(JDuplicate)。我看到java服务器使用DataInput.readUTF和DataInput.writeUTF方法,JDuplicate网站将其列为“java修改的UTF-8协议”

我的测试程序非常简单,我正在尝试发送客户端类型的数据,这应该会调用服务器的响应,但它只是超时:

#!/usr/bin/perl use strict; use Encode; use IO::Socket; my $remote = IO::Socket::INET->new( Proto => 'tcp', PeerAddr => 'localhost', PeerPort => '10421' ) or die "Cannot connect to server\n"; $|++; $remote->send(encode_utf8("CLIENTTYPE|JDSC#0.5.9#0.2")); while (<$remote>) { print $_,"\n"; } close($remote); exit(0); #!/usr/bin/perl 严格使用; 使用编码; 使用IO::Socket; my$remote=IO::Socket::INET->new( Proto=>“tcp”, PeerAddr=>“本地主机”, PeerPort=>“10421” )或“无法连接到服务器\n”; $|++; $remote->send(编码utf8(“CLIENTTYPE | JDSC#0.5.9#0.2”); 而(){ 打印美元“\n”; } 关闭(远程); 出口(0); 我试过$remote->send(pack(“U”)和“…”);,我尝试过“使用utf8;”,我尝试过binmode($remote,“:utf8”),我尝试过只发送纯ASCII文本,没有任何响应

我可以看到数据是通过tcpdump发送的,所有数据都在一个数据包中,但服务器本身对此不做任何处理(除了确认数据包)

我还需要做些什么来满足Java的“修改”utf实现吗


谢谢。

这与你问题的主要部分无关,但我想我会解释一下API所期望的“Java修改的UTF-8”是什么;它是UTF-8,除了UTF-16代理项对被编码为它们自己的代码点,而不是由UTF-8中直接编码的对表示的字符。例如,以字符
U+1D11E音乐符号G CLEF
为例

  • 在UTF-8中,它被编码为四个字节
    F0 9D 84 9E
  • 在UTF-16中,因为它超出了
    U+FFFF
    ,所以它使用代理项对
    0xD834 0xDD1E
    进行编码
  • 在“修改的UTF-8”中,给出了代理项对代码点的UTF-8编码:也就是说,将
    “\uD834\uDD1E”
    编码到UTF-8中,给出
    ED A0 B4 ED B4 9E
    ,正好有六个字节长
使用此格式时,Java还将使用非法超长形式
C080
对任何嵌入的空值进行编码,而不是将其编码为空值,以确保“修改的UTF-8”字符串中永远不存在任何嵌入的空值

但是,如果您没有发送BMP之外的任何字符或任何空字符,则与实际情况没有区别;)

以下是一些建议。

您必须正确实施:

首先,计算表示
s
的所有字符所需的总字节数。如果此数字大于65535,则引发
UTFDataFormatException
。否则,该长度完全按照方法的方式写入输出流;在此之后,将写入字符串
s
中每个字符的一字节、两字节或三字节表示形式

writeShort
文档所示,它以网络顺序发送16位数量

在Perl中,这类似于

sub sendmsg {
  my($s,$msg) = @_;

  die "message too long" if length($msg) > 0xffff;

  my $sent = $s->send(
    pack(n => (length($msg) & 0xffff)) .
    $msg
  );

  die "send: $!"    unless defined $sent;
  die "short write" unless $sent == length($msg) + 2;
}

sub readmsg {
  my($s) = @_;
  my $buf;
  my $nread;

  $nread = $s->read($buf, 2);
  die "read: $!"   unless defined $nread;
  die "short read" unless $nread == 2;

  my $len = unpack n => $buf;

  $nread = $s->read($buf, $len);
  die "read: $!"   unless defined $nread;
  die "short read" unless $nread == $len;

  $buf;
}
尽管上面的代码不执行修改的UTF编码,但它会引发一个响应:

my $remote = IO::Socket::INET->new(
  Proto => 'tcp',
  PeerAddr => 'localhost',
  PeerPort => '10421'
) or die "Cannot connect to server: $@\n";

my $msg = "CLIENTTYPE|JDSC#0.5.9#0.2";

sendmsg $remote, $msg;

my $buf = readmsg $remote;
print "[$buf]\n";
输出:

[SERVERTYPE|JDuplicate#0.5.9 beta (build 584)#0.2]
[SERVERTYPE | JDuplicate#0.5.9测试版(build 584)#0.2]完美!这正是我想要的。我现在能够像预期的那样来回交流了。非常感谢。