有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Perl客户端到Java服务器

我试图编写一个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);

我试过$remote->;发送(包(“U”和“…”);,我尝试过“使用utf8;”,我尝试过binmode($remote,“:utf8”),我尝试过只发送纯ASCII文本,没有任何响应

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

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

谢谢


共 (2) 个答案

  1. # 1 楼答案

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

    • 在UTF-8中,它被编码为四个字节F0 9D 84 9E
    • 在UTF-16中,因为它在U+FFFF之外,所以使用代理项对0xD834 0xDD1E进行编码
    • 在“modified UTF-8”中,它给出了代理项对代码点的UTF-8编码:也就是说,您将"\uD834\uDD1E"编码为UTF-8,给出了ED A0 B4 ED B4 9E,正好有六个字节长

    使用此格式时,Java还将使用非法超长形式C0 80对任何嵌入的空值进行编码,而不是将其编码为空值,从而确保“修改的UTF-8”字符串中永远不会有任何嵌入的空值

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

    这里有一些documentation courtesy of Sun

  2. # 2 楼答案

    您必须正确地实现protocol

    First, the total number of bytes needed to represent all the characters of s is calculated. If this number is larger than 65535, then a UTFDataFormatException is thrown. Otherwise, this length is written to the output stream in exactly the manner of the writeShort method; after this, the one-, two-, or three-byte representation of each character in the string s is written.

    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]