【问题标题】:Java UDP - Sending a string array from server to clientJava UDP - 将字符串数组从服务器发送到客户端
【发布时间】:2017-09-12 09:34:51
【问题描述】:

您好,提前致谢,

所以我试图获取一个 JList 项数组并将它们转换为一个字符串数组(我认为我做对了),然后我试图将该字符串数组发送给我的客户然后尝试将它们显示回他们身边的 JList。

我尝试了几种不同的方法,但都没有奏效。

这是我最近尝试发送字符串数组的代码:

String[] FilesList = (String[]) lClient1Files.getSelectedValues();

FilesBuffer = FilesList.getBytes();

DatagramPacket DGPFilesResponse = new DatagramPacket(FilesBuffer,FilesBuffer.length, DGP.getAddress(), DGP.getPort());
SeederSocket.send(DGPFilesResponse);

该行:FilesBuffer = FilesList.getBytes(); 导致问题,因为getBytes() 不适用于此处。

所以我的问题是: 1)我如何将 JList 项数组(它们是名称)发送到客户端(它不一定是字符串数组),以及 2) 我将如何在客户端接收列表,以便我可以使用它?

谢谢。

【问题讨论】:

  • Java 变量应该以小写字母开头。 String[] filesListfilesBuffer = filesList.getBytes()。听起来很琐碎,但如果 Java 程序员能够轻松阅读您的代码,他们会更容易回答您的问题。
  • 我明白了。谢谢。
  • 然而你没有编辑你的代码来适应 slim 的建议。

标签: java arrays compiler-errors


【解决方案1】:

必须为字符串数组制作二进制格式。

ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (DataOutputStream dos = new DataOutputStream(baos)) {
    dos.writeInt(filesList.length);
    for (String files : filesList) {
        dos.writeUTF(files);
    }
}
byte[] bytes = baos.toByteArray();

这在内部为字符串首先写入长度(以字节为单位),并使用String.getBytes("UTF-8"),因此可以写入任何字符串。

阅读与反向输入类一起使用。

如果您考虑有很多客户,也许有不同的版本, 然后在消息中添加一个版本号。


另一边

ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
try (DataInputStream dis = new DataInputStream(baos)) {
    int stringsCount = dis.readInt();
    String[] filesList = new String[stringsCount];
    for (int i = 0; i < stringsCount; ++i) {
        filesList[i] = dis.readUTF();
    }
    return filesList;
}

【讨论】:

  • @slim 是的,我有点懒:代码不是完全对称的。
  • 谢谢。它尝试了代码(并修复了对称性),我想出了一个错误:'线程“AWT-EventQueue-0”中的异常java.lang.ClassCastException:[Ljava.lang.Object;不能转换为 [Ljava.lang.String;' .该错误还说:在'ClientFrame1 $ 2.actionPerformed(ClientFrame1.java:161)'指的是这一行:'String [] FilesList =(String [])lClient1Files.getSelectedValues();'。我相信该数组无法从 JList 转换为 String 数组,但我不确定。是否有其他方法可以进行转换?
  • 查看docs.oracle.com/javase/8/docs/api/javax/swing/JList.html - (1) JList&lt;String&gt;,尤其是 (2) 应该使用 getSelectedValueList(),它返回一个 List&lt;String&gt; 而不是一个数组。
  • 你好。我尝试了您建议的代码,但出了点问题。没有错误,但我在接收方的阵列中没有得到任何东西。当我在客户端的 for 循环之外运行它时,我唯一能得到的是这条线: System.out.println(FilesList);它给出:[Ljava.lang.String;@158ce59b
  • 尝试System.out.println(Arrays.toString(FilesList)); - 查看数组中的内容。
【解决方案2】:

UDP 负载必须是byte[]。您需要选择一种方式将数据编码为byte[],以便在接收端将其转换回来。

所以你需要编写 encode()decode() 以便像这样的单元测试工作:

 @Test
 public void encodesAndDecodesStringArray() {
     String[] strings = new String[] { "foo", "bar" };
     byte[] encoded = Encoder.encode(strings);
     String[] decoded = Encoder.decode(encoded);

     assertThat(decoded, is(strings));
 }

实际上有数百种编码方案可供您选择。 Delimiter-separated、length-separated、JSON、XML、BSON、ASN.1……看看维基百科的List of data serialization formats

可能对您有用的一个非常简单的选项是分隔符分隔:

public byte[] encode(String[] strings) {
    return String.join(",", strings).getBytes(UTF_8);
}

public String[] decode(byte[] encodedArray) {
    return new String(encodedArray, UTF_8).split(",");
}

但请注意,如果任何输入字符串包含“,”(或您选择的任何分隔符),这个非常基本的方案就会失败。选择适合您的方案。

考虑使用 JSON —— 有易于使用的库来读取和写入 JSON。网络跟踪中的可读 ASCII 通常很方便。空间开销并不高。它适用于任意复杂的分层数据结构。

请考虑,如果您更改发送方生成的数据结构,接收方也必须更改。如果这很重要,请考虑将协议版本编码到您发送的内容中(只需说“前两个字节是版本”就足够了,并始终在其中粘贴0x0001)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-02
    • 1970-01-01
    • 2016-06-12
    • 1970-01-01
    • 2013-04-28
    • 1970-01-01
    • 2012-05-14
    相关资源
    最近更新 更多