StreamCorruptedException: invalid type code: AC异常分析

今天在写套接字相关的网络传输代码时碰到了这个异常,所以研究了一下,下面将该问题具象化为以下代码来说明该异常的起因和避免方法:

public class Server01 {
    public static void main(String[] args) throws IOException, InterruptedException {
        ServerSocket serverSocket = new ServerSocket(8888);

        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("d:\\pic.gif"));

        Socket socket = serverSocket.accept();
        
        byte[]buf=new byte[1024];
        int readLen=0;
        while((readLen=bufferedInputStream.read(buf))!=-1){
            Transmission transmission = new Transmission();
            transmission.setReadLen(readLen);
            byte[]buf2=transmission.getBuf();
            for (int i = 0; i <readLen ; i++) {
                buf2[i]=buf[i];
            }

            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());//每次传输过程都有一个新的ObjectInputStream类对象
            objectOutputStream.writeObject(transmission);

        }

        Thread.sleep(1000*1200);//避免服务端套接字过快关闭,而客户端正在读取套接字中的数据,而导致的EOF异常
        serverSocket.close();
        socket.close();
    }
}
public class Client01 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);

        ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());//只有这一个ObjectInputStream对象
        while(true) {
            Transmission transmission = (Transmission) objectInputStream.readObject();
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("D:\\pic3.gif",true));
            bufferedOutputStream.write(transmission.getBuf(),0,transmission.getReadLen());
            bufferedOutputStream.close();
        }
    }
}
public class Transmission implements Serializable {
    private byte[]buf=new byte[1024];
    private int readLen;

    public int getReadLen() {
        return readLen;
    }

    public void setReadLen(int readLen) {
        this.readLen = readLen;
    }

    public byte[] getBuf() {
        return buf;
    }
}

上面的代码在服务端运行起来后,再启动客户端,然后客户端进程就会抛出异常,抛出异常的位置如下:

Transmission transmission = (Transmission) objectInputStream.readObject();

其实这是因为

ObjectOutputStream实例在第一次进行序列化时会额外添加一个head,后面继续使用该对象实例进行序列化传输的时候省去了这一个步骤,而ObjectInputStream 实例在第一次反序列化时会去掉head,然后在后续使用该对象实例进行反序列化时就直接读取,不再有去掉head的操作。上述代码的服务端每次循环都会重新new一个ObjectOutputStream对象来进行序列化,导致每次循环进行序列化后都会额外添加一个head,而客户端每次反序列化都用的是同一个ObjectInputStream 实例对象,导致只有在第一次循环进行反序列化对象时会去掉一个head,而后续的读取不会进行该操作。这样就导致ObjectOutputStream进行序列化加入的head没有被ObjectOutputStream反序列化完全去掉,就会出问题。

所以这里有两个解决方案

第一,让客户端和服务端保持匹配,客户端中的ObjectInputStream对象实例在每次循环时重新new一个

​
public class Client01 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);


        while(true) {
            ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());

            Transmission transmission = (Transmission) objectInputStream.readObject();
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("D:\\pic3.gif",true));
            bufferedOutputStream.write(transmission.getBuf(),0,transmission.getReadLen());
            bufferedOutputStream.close();
        }
    }
}

​

第二,让服务端与客户端保持一致,服务端也是自始至终都只使用同一个ObjectOutputStream实例对象

public class Server01 {
    public static void main(String[] args) throws IOException, InterruptedException {
        ServerSocket serverSocket = new ServerSocket(8888);

        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("d:\\pic.gif"));

        Socket socket = serverSocket.accept();

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());

        byte[]buf=new byte[1024];
        int readLen=0;
        while((readLen=bufferedInputStream.read(buf))!=-1){
            Transmission transmission = new Transmission();
            transmission.setReadLen(readLen);
            byte[]buf2=transmission.getBuf();
            for (int i = 0; i <readLen ; i++) {
                buf2[i]=buf[i];
            }

            objectOutputStream.writeObject(transmission);

        }

        Thread.sleep(1000*1200);//避免服务端套接字过快关闭,而客户端正在读取套接字中的数据,而导致的EOF异常
        serverSocket.close();
        socket.close();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值