Java에서 객체 IO가 수행되는 프로젝트에서 작업 중입니다. 이 문제는 서버에있는 ObjectOutputStream에 의해 전송 된 객체가 클라이언트가받은 클래스와 같지 않은 클라이언트와 서버 사이의 관계에 있습니다.ObjectInputStream에 의해 수신 된 객체가 ObjectOutputStream에 의해 전송 된 객체와 같지 않음
여기에 작성된 ClientLoop 클래스는 클라이언트에 존재하지 않습니다. 클라이언트에 존재하지 않습니다. (혼란을 피하기 위해이 코드를 변경해야합니다.) ClientLoop은 Socket에서 클라이언트별로 만들어지며, 감지되어 서버와의 연결이 설정됩니다. 클라이언트에 의해 에게 전송 된 다음 객체를 수신하고이를 작업 파이프 라인 아래로 보내면 작업이 결정됩니다.
A question possibly anticipating the underlying technology from the object streams
public class ClientLoop extends Loop implements Sendable {
private final Commander commander;
private final Socket socket;
private final ObjectInputStream input;
private final ObjectOutputStream output;
private final Server server;
public ClientLoop(Server server, Socket socket) throws IOException {
this.server = server;
this.socket = socket;
//we need to construct the output stream first
//to discard the stream header
this.output = new ObjectOutputStream(socket.getOutputStream());
this.input = new ObjectInputStream(socket.getInputStream());
this.commander = new Commander(server, socket, this);
}
@Override
public void loop() {
try {
try {
Object next = input.readObject();
String className = next.getClass().getName();
System.out.println("Server Receive: " + next);
if (className.equals("com.meti.server.util.Command")) {
commander.runCommand(castIfOfInstance(next, Command.class));
//this section of code here says that whenever an AssetChange is being sent by the client.
} else if (next instanceof AssetChange) {
AssetChange assetChange = castIfOfInstance(next, AssetChange.class);
assetChange.update(server.getAssetManager().getAsset(assetChange.getAssetPath()));
//has been change, update all clientloops
} else {
getInstance().log(Level.WARNING, "Found no type handling " +
"for class type " + className);
}
} catch (EOFException e) {
socket.close();
setRunning(false);
}
} catch (Exception e) {
getInstance().log(Level.WARNING, e);
}
}
@Override
public void send(Serializable serializable, boolean flush) throws IOException {
System.out.println("Server Send: " + serializable);
output.writeObject(serializable);
if (flush) {
output.flush();
}
}
}
사령관 클래스는 여기에, 클래스가 너무 어렵 따라하는 것 ClientLoop 클래스에서 추가 기능을 제공하는 것입니다. 명령을 실행하는 메소드를 저장하기 위해서만 존재합니다. 그것은 아마도 최상의 코드 구조가 아니며 나중에 수정하게 될 것입니다.
public class Commander {
private Server server;
private Socket socket;
private Sendable sendable;
public Commander() {
}
public Commander(Server server, Socket socket, Sendable sendable) {
this.server = server;
this.socket = socket;
this.sendable = sendable;
}
public void runCommand(Command next) throws IOException {
if ("login".equals(next.getName())) {
String password = (String) next.getArgs()[0];
if (password.equals(server.getPassword())) {
getInstance().log(Level.INFO, "Client " + socket.getInetAddress() + " has connected with valid password");
} else {
getInstance().log(Level.INFO, "Client has invalid password, kicking out!");
socket.close();
}
} else if ("disconnect".equals(next.getName())) {
socket.close();
} else if ("list".equals(next.getName())) {
Cargo<String> cargo = new Cargo<>();
HashMap<String, Asset<?>> assets = server.getAssetManager().getAssets();
ArrayList<String> paths = new ArrayList<>();
paths.addAll(assets.keySet());
cargo.getContents().addAll(paths);
sendable.send(cargo, true);
} else if ("get".equals(next.getName())) {//should be declared other side...
String path = Utility.castIfOfInstance(next.getArgs()[0], String.class);
Asset<?> asset = server.getAssetManager().getAsset(path);
sendable.send(asset, true);
}
}
}
다음은 최신 실행 세션의 로그입니다. "서버 수신"이라고 할 때마다 서버는 클라이언트로부터 전송 된 객체를 찾았으며 "서버 전송"이라고 말하면 서버가 전송 한 객체가 될 것이며 ObjectInputStream 및 ObjectOutputStream을 통해 전송됩니다. 그렇지 않으면 일반 콘솔 명령문입니다. 로그 끝에 서버가 "Server Send : Asset {file = Nexus \ sample.txt, content = Hello Server! asdxc}"라는 개체를 보냈 음을 알 수 있습니다. ("asdxc"라는 문구는 테스트 중에 버튼 매시로 만들어졌으며 코드의 의미는 포함되어 있지 않습니다.)
그러나 위의 진술 문에있는 내용은 "Receive : Asset {file = Nexus \ sample .txt, content = Hello 서버!} ".
이 로그 출력에서 결론적으로 클라이언트의 ObjectInputStream과 서버의 ObjectOutputStream이 실제로 올바르게 작동하지만 서버의 ObjectOutputStream에서 전송 된 객체가 ObjectInputStream에서 즉시 수신 한 객체와 같지 않습니다. 클라이언트. 로그에 따르면 클라이언트가 올바르게 등록하지 않은 개체가 서버에서 보낸 개체 하나뿐이었습니다.
Oct 31, 2017 8:11:11 AM com.meti.Main log
INFO: Starting application
Oct 31, 2017 8:11:50 AM com.meti.Main log
INFO: Reading directory
Oct 31, 2017 8:11:51 AM com.meti.Main log
INFO: Listening for clients
Oct 31, 2017 8:11:53 AM com.meti.Main log
INFO: Located client at /127.0.0.1
Server Receive: Command{name='login', args=[5875580034436271440]}
Oct 31, 2017 8:11:53 AM com.meti.Main log
INFO: Client /127.0.0.1 has connected with valid password
Server Receive: Command{name='list', args=[files]}
Server Send:[email protected]
Server Receive: Command{name='get', args=[Nexus\sample.txt]}
Server Send:Asset{file=Nexus\sample.txt, content=Hello Server!}
Receive: Asset{file=Nexus\sample.txt, content=Hello Server!}
Server Receive: [email protected]
Server Receive: [email protected]
Server Receive: [email protected]
Server Receive: [email protected]
Server Receive: [email protected]
Server Receive: [email protected]
Server Receive: [email protected]
Server Receive: Command{name='get', args=[Nexus\sample.txt]}
Server Send:Asset{file=Nexus\sample.txt, content=Hello Server!asdxc}
Receive: Asset{file=Nexus\sample.txt, content=Hello Server!}
더 많은 코드가 문제를 진단하는 데 필요한 경우,이 GitHub의 링크에서 전체 코드베이스를 가지고 : https://github.com/Mathhman/Nexus
오류를 다시 만드는 작은 코드 조각을 만들 수 있습니까? – phflack