Java网络编程invalid stream header

简易多人聊天室项目
跟着b站韩顺平老师做的,自己有一些小改动。为什么总是出现这个错误啊java.io.StreamCorruptedException: invalid stream header,实在检查不出来哪里出的问题。下面是源码压缩包,提取码: b8gx
package com.company.Server.model;

/**
 * @Title:
 * @Package
 * @Description: 服务器和客户端通信线程
 * @author: Yeeasy
 **/

import com.company.Client.tools.TalkingViewManage;
import com.company.Client.tools.UserThreads;
import com.company.Client.tools.UserThreadsManage;
import com.company.Client.view.TalkingView;
import com.company.Shared.Message;

import java.net.*;
import java.io.*;

public class ConnectThread extends Thread {

    Socket socket;

    public ConnectThread(Socket socket) {
        this.socket = socket;
    }

    public void run() {

        while (true) {

            try {
                //接受信息
                ObjectInputStream in;
                ObjectOutputStream out;

                in = new ObjectInputStream(socket.getInputStream());
                Message msg = (Message) in.readObject();

                //从usersThread中获取friend线程,转发信息
                UserThreads userThread= UserThreadsManage.getUserThreads(msg.getUser());

                out = new ObjectOutputStream(userThread.getSocket().getOutputStream());
                out.writeObject(msg);

                TalkingView talkingView= TalkingViewManage.getTalkingView(msg.getUser());
                talkingView.showMessage(msg);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}


只要一登陆成功就会报 invalid stream header,然后开始聊天就会报空指针,实在不知道怎么办。

img

认真检查了线程和socket,找不到问题
[](链接: https://pan.baidu.com/s/1bqGp-WIHbqgFe_2PJtPr_w?pwd=b8gx)

你这里有三个问题:

  1. ConnectToServer 类 44行,为啥还要去在输出一次msg,就是这个导致了 invalid header ,注释之后这个异常就没了。

    img

  2. ActListener 类 47 行应该换成下面这个,要不然后面ConnectThread 里面 getUserThreads 会报空指针,你可能会觉得你的客户端有添加,但是客户端和服务端是两个独立的进程,内存不共享的。
    UserThreadsManage.addUserThreads(u.getUserID(), new UserThreads(socket));
    
  3. ConnectThread 类中 45 行代码获取 TalkingView,和上面情况一样。那个是客户端add进去的,服务端无法获取,另外服务端也没法add,因为add了获取到的也不是客户端的那个 TalkingView。
    TalkingView talkingView= TalkingViewManage.getTalkingView(msg.getUser());
    

而且正常服务端也应该是通过socket 转发消息给客户端,而不是直接操作客户端的界面显示

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 帮你找了个相似的问题, 你可以看下: https://ask.csdn.net/questions/190865
  • 除此之外, 这篇博客: java.io.StreamCorruptedException: invalid stream header中的 问题描述 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    问题:

    在一个用户给另一个仍未上线的用户(即离线用户)发送消息时,由于对方用户离线,服务端会将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();
                }
            }
        }
    }
    

    客户端

    // 客户端全部代码都在上面放了
    


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^