簡體   English   中英

發送文件后Stream沒有關閉

[英]Stream isn't closing after sending file

對不起,我對溪流的理解正在慢慢建立。

我最初嘗試將音樂文件流式傳輸到我的客戶端,但是沒有成功,所以我通過字節傳輸整個文件,然后在客戶端保存它。 問題是輸入流仍在接收字節,因此不會突破while循環(我想播放歌曲的位置)

以下是我的客戶端代碼的一部分:

//This is part of a task that carries this out (Part of a UI application)
@Override
protected Void call()
{
    try(Socket socket = new Socket(host,portNumber); 
        ObjectOutputStream toServer = new ObjectOutputStream(socket.getOutputStream());
        ObjectInputStream fromServer = new ObjectInputStream(socket.getInputStream()))
    {
        //Client requests a song from the server (song is a String)
        toServer.writeUTF(".Music."+song);
        toServer.flush();

        //Create a new file (tempSong is a string)
        File test = new File(tempSong);
        test.createNewFile();

        //New file writer
        BufferedOutputStream bOS = new BufferedOutputStream(new FileOutputStream(test));

        byte[] buffer = new byte[4096];
        int current;

        /** 
         * Read the bytes from the server and write the file
         * The file is written and I can play it (externally)
         * but the while loop doesn't break after writting the file
         */
        while ((current = fromServer.read(buffer)) > 0)
        {
            bOS.write(buffer, 0 , current);
        }

        System.out.println("Finished writing");

        bOS.close();

        /**
         * down here a method is ran to play the file
         * but it never happen because the task is still in the while loop
         */
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
    return null;
}

下面是服務器讀取消息並發送文件的服務器

/** This is part of a task and the main call area */
@Override
public Void call ()
{
    try
    {
        //Setup I/O
        toClient = new ObjectOutputStream(socket.getOutputStream());
        ObjectInputStream fromClient = new ObjectInputStream(socket.getInputStream());

        while(!socket.isClosed())
        {
            //If server has received a message
            if(fromClient.available() > 0)
            {
                //Reads message and objects from client
                String input = fromClient.readUTF();

                if (input.contains(".Music"))
                {
                    findMusic(input, toClient);
                }

                /**
                 * more else IFs
                 */
            }
        }
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
    return null;
}
/**
 * this method is part of the task discussed above
 */
//The method that is called
private void findMusic(String input, ObjectOutputStream toClient)
{
    logoff();
    String[] names = input.split("[.]");
    clientManagerTemp.logger("Someone request song: " + names[2] + ".mp3");

    File musicFile = AudioUtil.getSoundFile("src/Resources/Songs/" + names[2]+ ".mp3");
    byte[] buffer = new byte[(int) musicFile.length()];

    try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(musicFile)))
    {
        bis.read(buffer, 0, buffer.length);

        clientManagerTemp.logger("Sending " + "src/Resources/Songs/" + names[2]+ ".mp3" + "(" + buffer.length + " bytes)");
        //write the file to the client

        toClient.write(buffer,0, buffer.length);
        toClient.flush();

        clientManagerTemp.logger("Finished sending");

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

}

因此,您可以看到服務器發送文件正常,我的客戶端收到它。 它只是不會停止while循環。 有人可以解釋原因嗎? 所以我可以更好地理解套接字上的流字節是如何工作的

**編輯當客戶端收到文件時,即使關閉客戶端和服務器,也可以播放

您可以將文件長度發送到客戶端,使用此信息客戶端知道何時退出循環。

服務器

private void findMusic(String input, ObjectOutputStream toClient)
{
    logoff();
    String[] names = input.split("[.]");
    clientManagerTemp.logger("Someone request song: " + names[2] + ".mp3");

    File musicFile = AudioUtil.getSoundFile("src/Resources/Songs/" + names[2]+ ".mp3");
    int fileLength = (int) musicFile.length();
    byte[] buffer = new byte[fileLength];

    try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(musicFile)))
    {
        bis.read(buffer, 0, buffer.length);

        clientManagerTemp.logger("Sending " + "src/Resources/Songs/" + names[2]+ ".mp3" + "(" + buffer.length + " bytes)");
        //write the file to the client

        toClient.writeInt(fileLength);
        toClient.write(buffer,0, buffer.length);
        toClient.flush();

        clientManagerTemp.logger("Finished sending");

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

客戶

byte[] buffer = new byte[4096];
int current;
int fileLength = fromServer.readInt();

while ( fileLength > 0 && (current = fromServer.read(buffer, 0, Math.min(4096,fileLength))) > 0)
{
    bOS.write(buffer, 0 , current);
    fileLength -= current;
}

這是由於javadocs在這里看到的read方法的本質。 此方法將阻塞,直到有數據,因此您的循環將永遠不會結束。 現在的原因是因為您從不關閉服務器端的流,只需刷新它,這會強制發送當前緩沖區中的所有數據,但不會關閉流。 如果從服務器端調用流上的.close(),則應退出客戶端的while循環並繼續播放代碼。

我沒有對此進行過測試,但是從文檔和簡要查看代碼來看,這似乎是個問題。

如果不關閉連接(服務器端),則不會有文件結束/流結束,並且客戶端將永遠運行循環,除非您配置了讀取超時。

如果在發送文件完成后不自動關閉循環,則首先將字節數(文件大小)發送給客戶端,然后發送文件本身。 這使得在客戶端只讀取確切數量的字節並在完成時關閉連接成為可能。 另外,您可以發送特殊序列並在客戶端檢查它們以標記流的結束。

編程失敗的原因是由於ObjectInputStream.read()的行為。 此方法阻塞,直到它已讀取某些數據或流已關閉。 由於您從未關閉流,因此永遠不會滿足第二個條件。 所以只有選項1.當數據到達時返回。 遺憾的是,沒有辦法識別文件的結尾,除非你自己定義它,例如通過發送一個唯一的序列或你可以識別的東西來打破 while循環。

例:

while ((current = fromServer.read(buffer)) > 0)
{  
      // example value 42 could be anything else as well
      if(current == -42) 
      {
          break;
      }
      bOS.write(buffer, 0 , current);
}

這樣做的缺點是,您的數據也可能包含這個特殊值,因此您必須考慮不同的可能性,例如將序列記憶最多3個值並將它們與“中斷序列”進行比較。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM