文件流到服务器

时间:2013-11-07 08:52:51

标签: delphi filestream

我正在尝试通过网络将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;

问题在程序尝试编写流时开始,因此我甚至不确定接收端是否正常工作

聚苯乙烯。我是一名初学者

2 个答案:

答案 0 :(得分:2)

首先,您要发送宽带,这意味着您必须使用:

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;

答案 1 :(得分:0)

首先是这段代码:

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播放该文件。如果您不将文件存储在服务器中,则只能在服务器和客户端位于同一台计算机上时播放该文件(除非媒体播放器使用url或网络路径作为FileName)。