2010-01-12 160 views
2

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

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

 
#!/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); 

我试过$的远程> send(pack(“U”,“...”));我试过“使用utf8;”,我试过binmode($ remote,“:utf8”),我试过发送纯ASCII文本,没有任何回应。

我可以看到使用tcpdump发送的数据,全部在一个数据包中,但服务器本身对它不做任何处理(除了数据包之外)。

有什么额外的我需要做以满足Java的“修改”的utf实现吗?

谢谢。

+0

什么是Java代码? –

回答

4

你必须正确地贯彻protocol

首先,计算为代表的s所有字符所需的字节总数。如果此数字大于65535,则会抛出UTFDataFormatException。否则,该长度将以writeShort方法的方式写入输出流;在此之后,写入字符串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: [email protected]\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]
+0

完美!这正是我所期待的。我现在可以像预期的那样来回沟通。谢谢。 –

+0

不客气!我很乐意提供帮助。 –

3

这与您的问题的主要部分无关,但我想我会解释API预期的“Java的已修改的UTF-8”是什么;它是UTF-8,除了UTF-16代理对被编码为自己的代码点,而不是通过直接在UTF-8中编码的对来代替代表。例如,采取字符U+1D11E MUSICAL SYMBOL G CLEF

  • 在UTF-8中,它被编码为四个字节0​​。
  • 在UTF-16中,因为它超出了U+FFFF,所以它使用代理对0xD834 0xDD1E编码。
  • 在“修改后的UTF-8”中,它给出了代理对码点的UTF-8编码:也就是说,您将"\uD834\uDD1E"编码为UTF-8,给出ED A0 B4 ED B4 9E,它恰好是完全6个字节长。

当使用这种格式,Java将同样使用非法超长形式C0 80而不是编码它们为空值编码任何嵌入的空值,确保有从来没有在“修订的UTF-8”字符串的任何嵌入的空值。

如果你不发送BMP或任何空之外的任何字符,虽然没有从真实的东西差异;)

这里的一些documentation courtesy of Sun

+0

好信息,谢谢澄清。 –