Delphi 文件流到服务器

Delphi 文件流到服务器,delphi,filestream,Delphi,Filestream,我正试图通过网络将mp3文件发送到服务器,在那里由媒体播放器播放。到目前为止,我的代码适用于字符串,但不适用于文件。有人能告诉我我做错了什么吗 这是源代码 客户: procedure TForm1.Button1Click(Sender: TObject); var MyStream : TFileStream; MP3 : TFileName; Len : Int64; begin MP3 := GetCurrentDir + '\Clocks.mp3'; MyStream

我正试图通过网络将mp3文件发送到服务器,在那里由媒体播放器播放。到目前为止,我的代码适用于字符串,但不适用于文件。有人能告诉我我做错了什么吗

这是源代码

客户:

procedure TForm1.Button1Click(Sender: TObject);
var
  MyStream : TFileStream;
  MP3 : TFileName;
  Len : Int64;
begin
  MP3 := GetCurrentDir + '\Clocks.mp3';
  MyStream := TFilestream.Create(MP3, fmOpenRead);
  try
    Len := Length(MP3);
    MyStream.WriteBuffer(Len, SizeOf(Len));
    MyStream.WriteBuffer(Pointer(MP3)^, Len * SizeOf(MP3));

    MyStream.Position := 0;

    TcpClient1.Active := True;
    TcpClient1.SendStream(MyStream);
    TcpClient1.Active := False;
  finally
    MyStream.Free
  end;
end;
服务器:

procedure TForm1.TcpServer1Accept(Sender: TObject;
  ClientSocket: TCustomIpClient);
var
  MP3 : TFileName;
  Len: Int64;
begin
  //Receives the message from the client
  ClientSocket.ReceiveBuf(Len, SizeOf(Len),0);
  SetLength(MP3, Len);
  ClientSocket.ReceiveBuf(Pointer(MP3)^,Len * SizeOf(MP3), 0);

  MediaPlayer1.FileName := MP3;
  MediaPLayer1.Open;
  MediaPlayer1.Play;
end;
当程序尝试写入流时,问题就开始了,所以我甚至不确定接收端是否工作


注:我是一名初级程序员

首先,您发送的是宽字符串,这意味着您必须使用:

Len :=Length(mp3) * SizeOf(Char);
其次,你不需要演员阵容。这应该很好:

myStream.Write(mp3[1],Len);
第三,如果tcpSocket是非阻塞的,那么您不能在发送流之后直接禁用它,这将在连接启动之前切断连接。使用事件来了解数据何时发送

要避免所有这些,请在流上使用TReader和TWriter。这样,您就不必关心两侧的字符串数据大小,只需关心流大小

提示:始终先发送一个神奇值(常量值),这样您就可以在另一端检查它是否是有效的数据包

以下是一种方法:

Procedure TForm1.WriteMP3File(aFilename:string);
var
  mData:  TMemoryStream;
  mFile:  TFilestream;
  mWriter:  TWriter;
Begin
  mData:=TMemoryStream.Create;
  try
    mFile:=TFileStream.Create(aFilename,fmOpenRead);
    try
      mWriter:=TWriter.Create(mData);
      try
        // Write header code, any number will do
        mWriter.WriteInteger($BABE);

        // Write the filename
        mWriter.WriteString(ExtractFileName(aFilename));

        //Write size of MP3 file
        mWriter.WriteVariant(mFile.Size);

        //Push all data into the mData stream
        mWriter.FlushBuffer;

        //Append MP3 file
        mData.CopyFrom(mFile,mFile.Size);
      finally
        mWriter.Free;
      end;

      mData.Position:=0;
      socket.sendstream(mData);

    finally
      mFile.Free;
    end;
  finally
    mData.Free;
  end;
end;
在服务器上以相反的方式读取:

Procedure TForm1.ReadMP3File(aMp3PlayPath:String;aStream:TStream);
var
  mReader:  TReader;
  mFileData:  TFileStream;
  mName:    String;
  mSize:    Int64;
Begin
  try

    mReader:=TReader.Create(aStream);
    try
      if mReader.ReadInteger=$BABE then
      Begin
        mName:=mReader.ReadString;
        mSize:=mReader.ReadVariant;
      end else
      raise exception.Create('Invalid datapackage error');
    finally
      mReader.Free;
    end;

    if mSize>0 then
    Begin
      mFileData:=TFileStream.Create(aMp3PlayPath + mName,fmCreate);
      try
        mFiledata.CopyFrom(aStream,mSize);
      finally
        mFiledata.Free;
      end;
    end;

    //Now you can play the file


  finally
    //Release stream or do it elsewhere
    aStream.Free;
  end;
end;
首先,该代码:

MyStream.WriteBuffer(Len, SizeOf(Len));
MyStream.WriteBuffer(Pointer(MP3)^, Len * SizeOf(MP3));
在这种情况下,您试图更改MP3文件内容,这会损坏您的MP3文件。幸运的是,您以
fmOpenRead
的形式打开了文件,这就是
MyStream.WriteBuffer
失败的原因

如果要将文件名发送到服务器,则必须单独发送(例如使用
TTcpClient.SendBuf

在服务器端,您当前只读取文件名,而忽略文件内容本身

ClientSocket.ReceiveBuf(Len, SizeOf(Len),0); // this reads length of the filename
SetLength(MP3, Len);
ClientSocket.ReceiveBuf(Pointer(MP3)^,Len * SizeOf(MP3), 0); // this reads filename itself
// Now you should receive file contents itself and store it on the server 

将文件存储在服务器上后,可以使用MediaPlayer1播放该文件。如果不将文件存储在服务器上,则只能在服务器和客户端位于同一台计算机上时播放该文件(除非media player使用url或网络路径作为文件名).

我不打算只发送文件名。如何声明我处理的文件不是文件名,或者我甚至需要声明MyStream:=TFilestream.Create(GetCurrentDir+'\Clocks.mp3',fmOpenRead);如果是,如果我无法指向文件名变量,如何设置缓冲区的大小。在Answare中添加了一个示例:)添加一个like并在答案上增加值:)如果我的评级足够高,我会m8,我确实喜欢它,但当我开始实现您的代码时,我在这里收到一条错误消息:mWriter:=TWriter.Create(mData);这样行吗?mWriter:=TWriter.Create(mData,0);好的,当我将文件存储在内存中时,我可以开始播放它,只有当它播放完后,我才能释放流。我说的对吗?要从内存播放,你必须使用更复杂的directMedia。将文件保存到文件流,然后播放该文件。mp3格式是否与mediaDirect兼容,或者我是否应该开始查找windows支持的特定于voip的编解码器。如果你想从内存中播放谷歌“delphi mp3播放器”,你可能会发现很多。有很多delphi编解码器包装器,但为了简单起见,我坚持使用基于文件的解决方案。