对不起,我对溪流的理解正在慢慢建立。
我最初尝试将音乐文件流式传输到我的客户端,但是没有成功,所以我通过字节传输整个文件,然后在客户端保存它。问题是输入流仍然在接收字节,因此不会突破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循环。有人可以解释原因吗?所以我可以更好地理解套接字上的流字节是如何工作的
**编辑 当客户端收到文件时,即使在关闭客户端和服务器之后也可以播放该文件
答案 0 :(得分:3)
您可以将文件长度发送给客户端,客户端知道该信息何时退出循环。
服务器强>
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;
}
答案 1 :(得分:2)
这是由于阅读方法的性质,见Javadocs。此方法将阻塞,直到有数据,因此您的循环将永远不会结束。现在的原因是因为您从不关闭服务器端的流,只需刷新它,这会强制发送当前缓冲区中的所有数据,但不会关闭流。如果你从服务器端调用流上的.close(),那么应该退出客户端的while循环并继续你的播放代码。
我还没有对此进行过测试,但是从文档和简要查看代码来看,这似乎是个问题。
答案 2 :(得分:0)
如果您不关闭连接(服务器端),则不会有文件结束/流结束,并且您的客户端将永远运行循环,除非您配置了读取超时
如果您在发送文件完成后不想自动关闭循环,请先将字节数(文件大小)发送给客户端,然后再发送文件本身。这使得在客户端只读取确切数量的字节并在完成时关闭连接成为可能。 另外,您可以发送特殊序列并在客户端检查它们以标记流的结束。
答案 3 :(得分:0)
编程失败的原因是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个值并将它们与“中断序列”进行比较。