JAVA中在使用Socket从客户端项服务端传文件时,程序阻塞在获取Socket套接字输入流那一行是为什么?

这样写会阻塞在下面那一行,而调整位置后成功时什么问题,在我的理解中这一行的声明只要出现在使用之前就可以了。望解答,感谢

客户端上传文件程序

 Socket socket = new Socket("127.0.0.1", 8888);
        File file = new File("D:\\1610\\android素材\\bg04.jpg");
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
        **ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());**           //阻塞在这一行?我把这一行放在下面时该程序就运行成功,这之间有什么关系吗?希望大神解答,感谢!!!!
        System.out.println(file.getName());
        oos.writeUTF(file.getName());
        oos.writeLong(file.length());

        byte[] arr = new byte[1024];
        int len;
        while((len = bis.read(arr)) != -1){
            oos.write(arr,0,len);
            oos.flush();
        }
        //  上面那一行放在该位置
        System.out.println("1111");
        if(ois.readUTF().equals("下载成功")){
            System.out.println("文件上传成功");
            ois.close();
            oos.close();
            bis.close();
            socket.close();
        }

服务端接受文件代码块

 ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务器已启动...");
        while (true) {
            Socket socket = serverSocket.accept();
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            //这个位置
            String fileName=ois.readUTF();
            long extent = ois.readLong();
            System.out.println(extent);
            File file = new File("D:/TestFile");
            if (file.isDirectory()) {
                System.out.println("文件夹已存在");
            } else {
                file.mkdirs();
            }
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file.getAbsolutePath() +"/"+ fileName));
            BufferedWriter bw = new BufferedWriter(new FileWriter("down.log",true));
            _**ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());**_//或者是我把这一行放在上面位置也能成功
            byte[] arr = new byte[1024];
            int len;
            long total = 0;
            while ((len = ois.read(arr)) != -1) {
                bos.write(arr, 0, len);
                total += len;
                bw.write("当前已下载" + (total * 100) / extent + "%"
                        + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                bw.newLine();
                bw.flush();
                if (total == extent) {
                    oos.writeUTF("下载成功");
                    break;
                }
            }
            System.out.println("下载成功");
            oos.close();
            bw.close();
            bos.close();
            ois.close();
            socket.close();
        }

4个回答

看jdk官方的文档就知道答案了:
public ObjectInputStream(InputStream in)
throws IOException创建从指定 InputStream 读取的 ObjectInputStream。从流读取序列化头部并予以验证。在对应的 ObjectOutputStream 写入并刷新头部之前,此构造方法将阻塞。

                                这时候socket.getInputStream()还没有数据流过来,所以就等待数据,阻塞了
CrazyCoding123
CrazyCoding123 回复_1_1_7_: 谢谢,我再看看研究研究
接近 4 年之前 回复
u011606457
_1_1_7_ 正好你的客户端是先out再in,而服务器是先in再out;看jdk的源码就更清楚了,建议你平时多看看
接近 4 年之前 回复
u011606457
_1_1_7_ 回复CrazyCoding123: public ObjectOutputStream(OutputStream out) throws IOException创建写入指定 OutputStream 的 ObjectOutputStream。此构造方法将序列化流部分写入基础流;调用方可以通过立即刷新流,确保在读取头部时,用于接收 ObjectInputStreams 构造方法不会阻塞。
接近 4 年之前 回复
CrazyCoding123
CrazyCoding123 可是你看我上面第二条回答,为什么客户端和服务端都写在一起就是可以的呢,这时候没有数据流过来,也并没有阻塞
接近 4 年之前 回复

你的服务器要先读
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务器已启动...");
while (true) {
Socket socket = serverSocket.accept();
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
//这个位置
String fileName=ois.readUTF();-----------------服务器要先读取数据,那客户端肯定得先发数据。

                    客户端先发数据,就得先获得输出流,往套接字中输出  写数据,让服务器去接收,所以
                    Socket socket = new Socket("127.0.0.1", 8888);
    File file = new File("D:\\1610\\android素材\\bg04.jpg");
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));  --------------执行到这一行肯定没问题。

            问题是,客户端接受服务器的数据时,才用到*ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());---也就是客户端什么时候接服务器的数据,什么时候才需要这行,其他时候肯定阻塞,因为tcp接收数据的方法都是阻塞方法,可以看下源代码,都是加锁了的。
CrazyCoding123
CrazyCoding123 你看下面我的回答,还有问题,谢谢你啦
接近 4 年之前 回复

可是我的客户端开头这两个获取写在开头

 Socket socket = new Socket("127.0.0.1", 8888);
        File file = new File("D:\\1610\\android素材\\bg04.jpg");
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
        **ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());**           //阻塞在这一行?我把这一行放在下面时该程序就运行成功,这之间有什么关系吗?希望大神解答,感谢!!!!

服务端也同时写在开头

  ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务器已启动...");
        while (true) {
            Socket socket = serverSocket.accept();
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
_**ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());**_//这行也放在这

这不是什么时候接收数据什么时候定义这行,为什么这样就也是成功的
就是分开什么时候用到什么时候写或者都写一起都是成功的

public ObjectOutputStream(OutputStream out) throws IOException {
verifySubclass();
bout = new BlockDataOutputStream(out);
handles = new HandleTable(10, (float) 3.00);
subs = new ReplaceTable(10, (float) 3.00);
enableOverride = false;

** writeStreamHeader();**

public ObjectInputStream(InputStream in) throws IOException {
verifySubclass();
bin = new BlockDataInputStream(in);
handles = new HandleTable(10);
vlist = new ValidationList();
enableOverride = false;

** readStreamHeader();**

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问