Exception in thread "main" java.io.StreamCorruptedException: invalid stream header: 4E000000
读取输入流的过程中发现了无效的流头。这可能是因为输入流的格式不正确导致的。具体原因可能是文件损坏、文件类型不匹配、文件编码格式错误
基于new bing部分指引作答:
该错误通常表示在尝试反序列化对象时发生了问题。StreamCorruptedException异常一般出现在以下几种情况下:
序列化和反序列化的版本不匹配:如果尝试使用不同版本的Java进行序列化和反序列化操作,就会导致该异常。请确保序列化和反序列化的代码在相同的Java版本下运行。
对象的类定义已更改:如果你在序列化对象之后修改了对象的类定义,再进行反序列化会导致异常。确保在反序列化之前,对象的类定义没有发生变化。
使用错误的输入源进行反序列化:请检查你正在读取的输入源是否正确。例如,如果你尝试从非序列化的数据中读取,就可能导致该异常。
针对你提到的错误信息 "java.io.StreamCorruptedException: invalid stream header: 4E000000",这可能是由于解析非序列化数据或数据损坏引起的。请确保你的输入源是正确的,并且数据没有损坏。
不知道你这个问题是否已经解决, 如果还没有解决的话:问题:
在一个用户给另一个仍未上线的用户(即离线用户)发送消息时,由于对方用户离线,服务端会将message先存储起来,等待该用户上线再转发message给他。但是当我这样处理的时候,出现了如下错误。
java.io.StreamCorruptedException: invalid stream header: 7371007E
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:936)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:394)
at com.hspedu.qqclient.service.ClientConnectServerThread.run(ClientConnectServerThread.java:23)
而且,我发现,该离线用户一旦上线,服务端是会正常发送他离线期间收到的信息给他的,关键是接收出了问题。
服务端没有报错:
客户端报错,但是它是在收到一条正确的离线留言之后才产生错误的:
给出关键源代码如下:
服务端
// 将离线消息都发过去
oos=new ObjectOutputStream(ManageClientThreads.getClientThread(user.getUserId()).getSocket().getOutputStream());
if(offlineDb.containsKey(user.getUserId())){
ArrayList<Message> messages = offlineDb.get(user.getUserId());
for (Message offlinems:messages
) {
System.out.println(offlinems.getContent());
oos.writeObject(offlinems);
}
offlineDb.remove(user.getUserId());
System.out.println(user.getUserId()+"上线了,服务端已经转发完成所有离线消息");
}
客户端
package com.hspedu.qqclient.service;
import com.hspedu.qqcommon.Message;
import com.hspedu.qqcommon.MessageType;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
public class ClientConnectServerThread extends Thread{
// 该线程需要持有socket对象
private Socket socket;
//构造器接收socket
public ClientConnectServerThread(Socket socket) {
this.socket = socket;
}
private ObjectInputStream ois;
@Override
public void run() {
// 因为Thread需要后台和服务器通信,所以我们一直循环
while(true){
System.out.println("客户端线程,等待读取从服务器端发送过来的消息");
try {
ois= new ObjectInputStream(socket.getInputStream());
// 如果服务器没有发送Message对象,线程就会阻塞在这里
Message message=(Message)(ois.readObject());
//如果读取到的是服务端返回的在线用户列表
if(message.getMesType().equals(MessageType.MESSAGE_RET_ONLINE_FRIEND)){
//取出在线列表信息并显示
String[] onlineUsers=message.getContent().split(" ");
System.out.println("============当前在线用户列表=============");
for (int i = 0; i < onlineUsers.length; i++) {
System.out.println(onlineUsers[i]);
}
}else if(message.getMesType().equals(MessageType.MESSAGE_COMM_MES)){
//收到私聊信息
System.out.println("我"+message.getGetter()+"收到了来自"+message.getSender()+"的私聊信息:"+message.getContent());
}else if(message.getMesType().equals(MessageType.MESSAGE_TO_ALL_MES)){
//收到群发信息
System.out.println("我收到了来自"+message.getSender()+"的群发信息:"+message.getContent());
}else if(message.getMesType().equals(MessageType.MESSAGE_NEWS)){
System.out.println("我收到了来自服务端推送的新闻:"+message.getContent());
}
else{
System.out.println("是其他类型的message,暂时不处理");
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
}
该文件全部源代码:
服务端
package com.hspedu.qqserver.service;
import com.hspedu.qqcommon.Message;
import com.hspedu.qqcommon.MessageType;
import com.hspedu.qqcommon.User;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
public class QQServer {
private ServerSocket ss = null;
// 创建一个集合,存放多个用户,如果是这些用户登录,就认为合法
private static HashMap<String, User> validUsers = new HashMap<>();
private static HashMap<String, ArrayList<Message>> offlineDb =new HashMap<>();
static {//在静态代码块内初始化validUsers
validUsers.put("100", new User("100", "123456"));
validUsers.put("200", new User("200", "123456"));
validUsers.put("300", new User("300", "123456"));
validUsers.put("李东海", new User("李东海", "李赫宰"));
validUsers.put("李赫宰", new User("李赫宰", "李东海"));
}
public static HashMap<String, ArrayList<Message>> getOfflineDb() {
return offlineDb;
}
// 验证用户是否有效的方法
private boolean checkUser(String userId, String password) {
User user = validUsers.get(userId);
if (user != null && user.getPassword().equals(password)) {
return true;
}
return false;
}
public QQServer() {
System.out.println("服务端在9999端口监听...");
try {
ss = new ServerSocket(9999);
SendNewsToAllService sendNewsToAllService = new SendNewsToAllService();
sendNewsToAllService.start();
//当和某个客户端建立连接之后,会继续监听,因为应该用while循环
while (true) {
Socket socket = ss.accept();
//得到socket关联的对象输入流
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
//得到socket关联的对象输出流
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
User user = (User) (ois.readObject());
// 验证
Message message = new Message();
if (checkUser(user.getUserId(), user.getPassword())) {
message.setMesType(MessageType.MESSAGE_LOGIN_SUCCEED);
// 回复客户端一个Message对象
oos.writeObject(message);
//创建一个线程,和客户端保持通信,该线程需要持有socket对象
ServerConnectClientThread serverConnectClientThread = new ServerConnectClientThread(socket, user.getUserId());
// 启动线程
serverConnectClientThread.start();
// 把该线程对象放到集合中管理
ManageClientThreads.addClientThread(user.getUserId(), serverConnectClientThread);
// 将离线消息都发过去
oos=new ObjectOutputStream(ManageClientThreads.getClientThread(user.getUserId()).getSocket().getOutputStream());
if(offlineDb.containsKey(user.getUserId())){
ArrayList<Message> messages = offlineDb.get(user.getUserId());
for (Message offlinems:messages
) {
System.out.println(offlinems.getContent());
oos.writeObject(offlinems);
}
offlineDb.remove(user.getUserId());
System.out.println(user.getUserId()+"上线了,服务端已经转发完成所有离线消息");
}
} else {
System.out.println("登录失败");
message.setMesType(MessageType.MESSAGE_LOGIN_FAIL);
oos.writeObject(message);
socket.close();
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端
// 客户端全部代码都在上面放了