Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 袜子退火。无效的流标头:00000000_Java_Serialization_Nio_Bytebuffer_Socketchannel - Fatal编程技术网

Java 袜子退火。无效的流标头:00000000

Java 袜子退火。无效的流标头:00000000,java,serialization,nio,bytebuffer,socketchannel,Java,Serialization,Nio,Bytebuffer,Socketchannel,我想序列化“Message”对象,我可以通过socketChannel成功地将其作为字节数组传输。在那之后,我更改了对象的属性(以便它可能有更大的大小),然后将对象发送回客户端时出现问题。 一旦我尝试在客户端获取对象,我会得到一个异常,当我在getResponse()方法中反序列化消息obj时会发生: 但是,不知何故,这只适用于第一个客户机(抛出异常后,与第一个客户机的连接结束),当我启动一个新客户机(而不是关闭服务器)时,我可以成功地来回传输对象,而且,它适用于任何新客户机 这是我的最低可调试

我想序列化“Message”对象,我可以通过socketChannel成功地将其作为字节数组传输。在那之后,我更改了对象的属性(以便它可能有更大的大小),然后将对象发送回客户端时出现问题。 一旦我尝试在客户端获取对象,我会得到一个异常,当我在getResponse()方法中反序列化消息obj时会发生:

但是,不知何故,这只适用于第一个客户机(抛出异常后,与第一个客户机的连接结束),当我启动一个新客户机(而不是关闭服务器)时,我可以成功地来回传输对象,而且,它适用于任何新客户机

这是我的最低可调试版本:

import org.apache.commons.lang3.SerializationUtils;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Scanner;

public class Client {

    private SocketChannel server;

    public void start() throws IOException {
        try {
            server = SocketChannel.open(new InetSocketAddress("localhost", 5454));
            server.configureBlocking(false);
        } catch (IOException e) {
            System.err.println("Server isn't responding");
            System.exit(0);
        }

        Scanner scRequest = new Scanner(System.in);
        Scanner scState = new Scanner(System.in);


        System.out.println("Enter request:");
        String request = scRequest.nextLine();

        while (!request.equals("exit")) {
            try {
                // In my actual project class Person is a way different (But it's still a POJO)
                // I included it here to make sure I can get it back after sending to the server
                System.out.println("Enter a number:");
                Person person = new Person(scState.nextInt());
                sendRequest(request, person);

                System.out.println("\nEnter request:");
                request = scRequest.nextLine();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        stop();
    }

    public void sendRequest(String sMessage, Person person) {
        Message message = new Message(sMessage, person);
        ByteBuffer requestBuffer = ByteBuffer.wrap(SerializationUtils.serialize(message));
        try {
            server.write(requestBuffer);
            requestBuffer.clear();
            getResponse();
        } catch (Exception e) {
            System.out.println(e.getMessage());
            System.err.println("Connection lost");
            System.exit(0);
        }
    }

    public void getResponse() throws Exception {
        ByteBuffer responseBuffer = ByteBuffer.allocate(1024 * 1024 * 64);

        int read = server.read(responseBuffer);
        responseBuffer.clear();
        if(read == -1) {
            throw new Exception();
        }

        byte[] bytes = new byte[responseBuffer.limit()];
        responseBuffer.get(bytes);

        Message message = SerializationUtils.deserialize(bytes);
        System.out.println(message);
    }

    public void stop() throws IOException {
        server.close();
    }

    public static void main(String[] args) throws IOException {
        Client client = new Client();
        client.start();
    }
}
我在消息obj中包含此类的实例:

public class Person implements Serializable {
    private final int state;

    public Person(int state) {
        this.state = state;
    }

    @Override
    public String toString() {
        return "Person state: " + state;
    }
}
我不知道出了什么问题,希望你的帮助


UPD:我使用“org.apache.commons:commons-lang3:3.5”依赖项将对象序列化为字节数组

我以前从未使用过Java NIO通道,所以我不是专家。但我发现了几件事:

概述:

  • 为了调试代码,使用
    e.printStackTrace()
    而不仅仅是
    System.out.println(e.getMessage())
    是很有帮助的
客户端:

  • 客户端中的
    SocketChannel服务器
    应配置为阻塞,否则它可能读取0字节,因为还没有服务器响应,这会导致您的问题
  • 在阅读内容之前,而不是之后,您应该始终调用
    ByteBuffer.clear()
  • 读取后,在调用
    get(byte[])
    之前,必须通过
    responseBuffer.position(0)
    将字节缓冲区中的位置重置为0,否则它将在刚刚读取的字节之后读取未定义的字节
  • 您应该根据读取的字节数而不是字节缓冲区大小来调整字节数组的大小。它可能反过来工作,但效率很低
服务器:

  • 在阅读内容之前,而不是之后,您应该始终调用
    ByteBuffer.clear()
  • 读取后,在调用
    get(byte[])
    之前,必须通过
    responseBuffer.position(0)
    将字节缓冲区中的位置重置为0,否则它将在刚刚读取的字节之后读取未定义的字节
  • getRequest(key)
    调用期间捕获异常时,应关闭相应的通道,否则在客户端断开连接后,服务器将无限期地尝试从中读取,并向控制台日志发送带有错误消息的垃圾邮件。我的修改处理了这种情况,并打印了一条很好的日志消息,告诉我哪个客户端(远程套接字地址)已关闭
警告:您的代码中没有处理写入通道一侧的请求或响应大于另一侧的最大
字节缓冲大小的情况。类似地,理论上,(反)序列化的
字节[]
也可能最终比字节缓冲区大

这是我的差异,我希望你知道如何阅读差异:

索引:src/main/java/de/scrum\u master/stackoverflow/q65890087/Client.java
===================================================================
---a/src/main/java/de/scrum_master/stackoverflow/q65890087/Client.java(修订阶段)
+++b/src/main/java/de/scrum_master/stackoverflow/q65890087/Client.java(日期1612321383172)
@@ -15,7 +15,7 @@
public void start()引发IOException{
试一试{
server=SocketChannel.open(新的InetSocketAddress(“localhost”,5454));
-server.configureBlocking(false);
+server.configureBlocking(true);
}
捕获(IOE异常){
System.err.println(“服务器未响应”);
@@ -56,22 +56,24 @@
getResponse();
}
捕获(例外e){
-System.out.println(e.getMessage());
+e.printStackTrace();
+//System.out.println(e.getMessage());
System.err.println(“连接丢失”);
系统出口(0);
}
}
public void getResponse()引发异常{
-ByteBuffer responseBuffer=ByteBuffer.allocate(1024*1024*64);
+ByteBuffer responseBuffer=ByteBuffer.allocate(1024*1024);
+responseBuffer.clear();
int read=server.read(responseBuffer);
-responseBuffer.clear();
如果(读取==-1){
-抛出新异常();
+抛出新异常(“EOF,无法读取服务器响应”);
}
-byte[]bytes=新字节[responseBuffer.limit()];
+字节[]字节=新字节[读取];
+响应缓冲位置(0);
responseBuffer.get(字节);
Message Message=SerializationUtils.deserialize(字节);
索引:src/main/java/de/scrum_master/stackoverflow/q65890087/Server.java
===================================================================
---a/src/main/java/de/scrum_master/stackoverflow/q65890087/Server.java(修订阶段)
+++b/src/main/java/de/scrum_master/stackoverflow/q65890087/Server.java(日期1612323386278)
@@ -35,7 +35,11 @@
获取请求(密钥);
}
捕获(例外e){
-System.err.println(e.getMessage());
+e.printStackTrace();
+//System.err.println(e.getMessage());
+SocketChannel客户端=(SocketChannel)key.channel();
+System.err.println(“在以下位置关闭客户端连接:”+client.socket().getRemoteSocketAddress());
+client.close();
}
}
iter.remove();
@@ -45,15 +49,16 @@
private void getRequest(SelectionKey)引发异常{
SocketChannel客户端=(SocketChannel)key.channel();
-ByteBuffer requestBuffer=ByteBuffer.allocate(1024*1024*64);
+ByteBuffer requestBuffer=ByteBuffer.allocate(1024*1024);
+requestBuffer.clear();
int read=客户端读取(请求
import org.apache.commons.lang3.SerializationUtils;

import java.io.*;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class Server {

    public void start() throws IOException {

        Selector selector = Selector.open();
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.bind(new InetSocketAddress("localhost", 5454));
        serverSocket.configureBlocking(false);
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);

        System.out.println("Server started");

        while (true) {
            selector.select();
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> iter = selectedKeys.iterator();
            while (iter.hasNext()) {
                SelectionKey key = iter.next();
                if (key.isAcceptable()) {
                    register(selector, serverSocket);
                }
                if (key.isReadable()) {
                    try {
                        getRequest(key);
                    } catch (Exception e) {
                        System.err.println(e.getMessage());
                    }
                }
                iter.remove();
            }
        }
    }

    private void getRequest(SelectionKey key) throws Exception {
        SocketChannel client = (SocketChannel) key.channel();

        ByteBuffer requestBuffer = ByteBuffer.allocate(1024 * 1024);
        int read = client.read(requestBuffer);
        requestBuffer.clear();

        if(read == -1) {
            key.cancel();
            throw new Exception("Client disconnected at: " +
                    ((SocketChannel) key.channel()).socket().getRemoteSocketAddress());
        }

        byte[] bytes = new byte[requestBuffer.limit()];
        requestBuffer.get(bytes);

        Message message = SerializationUtils.deserialize(bytes);
        sendResponse(client, message);
    }

    private void sendResponse(SocketChannel client, Message message) throws IOException {

        message.setResult("Some result");

        ByteBuffer responseBuffer = ByteBuffer.wrap(SerializationUtils.serialize(message));
        while (responseBuffer.hasRemaining()) {
            client.write(responseBuffer);
        }
        responseBuffer.clear();
    }

    private void register(Selector selector, ServerSocketChannel serverSocket) throws IOException {
        SocketChannel client = serverSocket.accept();
        client.configureBlocking(false);
        client.register(selector, SelectionKey.OP_READ);
        System.out.println("New client at: " + client.socket().getRemoteSocketAddress());
    }

    public static void main(String[] args) throws Exception {
        new Server().start();
    }
}

import java.io.Serializable;
import java.util.Formatter;

public class Message implements Serializable {

    private String command;
    private Person person;
    private String result;

    public Message(String command, Person person) {
        this.command = command;
        this.person = person;
    }

    public String getCommand() {
        return command;
    }
    public void setCommand(String executedCommand) {
        this.command = executedCommand;
    }
    public Person getPerson() {
        return person;
    }
    public void setPerson(Person person) {
        this.person = person;
    }
    public String getResult() {
        return result;
    }
    public void setResult(String result) {
        this.result = result;
    }

    @Override
    public String toString() {
        return new Formatter()
                .format("Command: %s\nAttached object: %s\nResult: %s",
                        command, person, result)
                .toString();
    }
}
public class Person implements Serializable {
    private final int state;

    public Person(int state) {
        this.state = state;
    }

    @Override
    public String toString() {
        return "Person state: " + state;
    }
}