client:unit UnitClient;interfaceuses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ScktComp, StdCtrls, Buttons, ExtCtrls;
Const
MP_QUERY ='11111';
MP_REFUSE ='22222';
MP_ACCEPT ='33333';
MP_NEXTWILLBEDATA='44444';
MP_DATA ='55555';
MP_ABORT ='66666';
MP_OVER ='77777';
MP_CHAT ='88888';
MP_END='99999';
MP_FILEPROPERTY='00000';
iBYTEPERSEND=1024;type
  TForm1 = class(TForm)
    OpenDialog1: TOpenDialog;
    cs: TClientSocket;
    Memo1: TMemo;
    Panel1: TPanel;
    btnSendFile: TBitBtn;
    btnConnect: TBitBtn;
    edtIPAddress: TEdit;
    procedure btnConnectClick(Sender: TObject);
    procedure btnSendFileClick(Sender: TObject);
    procedure csRead(Sender: TObject; Socket: TCustomWinSocket);
    procedure FormCreate(Sender: TObject);
  private
    fsSend: TFileStream;
    bStart:Boolean;
    TickCount:Longword;
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;implementation{$R *.DFM}procedure TForm1.btnConnectClick(Sender: TObject);
begin
  cs.Address:=edtIPAddress.Text;
  cs.Port:=2000;
  cs.Open;
end;procedure TForm1.btnSendFileClick(Sender: TObject);
begin
  if OpenDialog1.Execute then
  Begin
    cs.Socket.SendText(MP_QUERY+OpenDialog1.FileName);
    //接收端是否准备好!
  end;
end;procedure TForm1.csRead(Sender: TObject; Socket: TCustomWinSocket);
var
  sRecv:string;
  bufSend:pointer;
  iLength:Integer;
begin
  sRecv:=Socket.ReceiveText;
  sRecv:=copy(sRecv,1,5);
  if sRecv=MP_REFUSE then
    memo1.Lines.Add('被拒绝!')
  else if sRecv=MP_ACCEPT then
  begin
    fsSend:=TFileStream.Create(OpenDialog1.FileName,fmOpenRead);
    bStart:=False;
    memo1.Lines.Add('开始发送!');
    TickCount:=GetTickCount;
    //iBYTEPERSEND是个常量,每次发送包的大小。
    Socket.SendText(MP_FILEPROPERTY+inttostr(Trunc(fsSend.Size/iBYTEPERSEND)+1));
    //创建文件流并发送文件长度。
  end else if sRecv=MP_NEXTWILLBEDATA then
  begin
    Socket.SendText(MP_NEXTWILLBEDATA);
    //通知接收端。继续传送数据。
  end else if sRecv=MP_DATA then
  begin
    //发送数据。
    if not bStart then
    begin
      memo1.Lines.Add('发送数据!');
      bStart:=True;
    end;
    if fsSend.Position< fsSend.Size-1 then//还有数据没有发送。
    begin
      iLength:=fsSend.Size-1-fsSend.Position;
      if iLength>iBYTEPERSEND then
        iLength:=iBYTEPERSEND;
      GetMem(bufSend,iLength+1);
      try
        fsSend.Read(bufSend^,iLength);
        Socket.SendBuf(bufSend^,iLength);
      finally
        FreeMem(bufSend,iLength+1);
      end;{of try}
    end else//没有数据需要发送了。
    begin
      Socket.SendText(MP_END);//文件传送结束。
      memo1.Lines.Add('结束!'+IntToStr(GetTickCount-TickCount));
      fsSend.Free;    //    <--------------------
    end;
  end else if sRecv=MP_ABORT then
  begin
    memo1.Lines.Add('中止!');
    //被取消了:(
    fsSend.Free;
  end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Clear;
end;end.
server:unit UnitServer;interfaceuses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons, ScktComp, ExtCtrls;
Const
  MP_QUERY ='11111';
  MP_REFUSE ='22222';
  MP_ACCEPT ='33333';
  MP_NEXTWILLBEDATA='44444';
  MP_DATA ='55555';
  MP_ABORT ='66666';
  MP_OVER ='77777';
  MP_CHAT ='88888';
  MP_END='99999';
  MP_FILEPROPERTY='00000';
type
  TForm1 = class(TForm)
    SaveDialog1: TSaveDialog;
    ss: TServerSocket;
    Memo1: TMemo;
    procedure ssClientRead(Sender: TObject; Socket: TCustomWinSocket);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    fsRecv:TFileStream;
    bStart:Boolean;
    TickCount:Longword;
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;implementation
{$R *.DFM}procedure TForm1.ssClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
  sTemp,sFileName:string;
  bufRecv:Pointer;
  iLength:Integer;
begin
  iLength:=Socket.ReceiveLength;
  GetMem(bufRecv,iLength);
  try
    Socket.ReceiveBuf(bufRecv^,iLength);   //
    sTemp:=StrPas(PChar(bufRecv));
    //如果传入的数据有可能不是字符串,需要用其他方式处理,则这里不能及Socket.ReceiveText方法取数据出来检查,
    //因为这个方法会清空接收缓冲区,也就是说在执行Socket.ReceiveText方法后,Socket.ReceiveLength将会返回0,
    //ReceiveBuf方法也不会取到正确数据。ReceiveBuf方法也是一样的!
    //所以在取数据前一定要先把长度取出来,保存在一个变量中。    //请注意判断第一个字符的方法有可能出问题,有可能传送文件的时候正好当前传送段的数据的第一个字节是一个0-9之间的字符。可能会出错。
    sTemp:=Copy(sTemp,1,5);
    if sTemp=MP_QUERY then
    begin
      sTemp:=Trim(StrPas(PChar(bufRecv)));
      sFileName:=ExtractFileName(Copy(sTemp,6,Length(STemp)));
      //在这里拒绝
      SaveDialog1.Title:='请选择或输入接收到的数据保存到的文件名:';
      SaveDialog1.FileName:=sFileName;
      if SaveDialog1.Execute then
      begin
        fsRecv:=TFileStream.Create(SaveDialog1.FileName,fmCreate);
        //如果愿意接收数据。
        memo1.Lines.Add ('开始接收!');//??????
        TickCount:=GetTickCount;
        Socket.SendText(MP_ACCEPT);
        //通知发送端发送数据。
        bStart:=False;
      end
      else
        Socket.SendText(MP_REFUSE+'去死');
    end else if sTemp=MP_FILEPROPERTY then
    begin
      //要发送StrToInt(Copy(sTemp,2,Length(sTemp))) 次
      //时间进度显示
      //iRecvLength:=StrToInt(Copy(sTemp,2,Length(sTemp)));//;1024
      Socket.SendText(MP_NEXTWILLBEDATA);
      //接收文件长度并要求继续传送数据。
    end else if sTemp=MP_NEXTWILLBEDATA then
    begin
      Socket.SendText(MP_DATA);
      //要求发送端发送数据。
      //准备好接收数据。
    end else if sTemp=MP_OVER then
    begin
      memo1.Lines.Add ('MP_OVER');//??????
      fsRecv.Free;
    end else if sTemp=MP_END then//文件传送结束。
    begin
      memo1.Lines.Add ('结束!'+IntToStr(GetTickCount-TickCount));//??????
      fsRecv.Free;
    end else if sTemp=MP_ABORT then
    begin
      memo1.Lines.Add ('MP_ABORT');//??????
      fsRecv.Free;
    end else if sTemp=MP_CHAT then
    begin
      //Chat Msg
    end else
    begin
      if not bStart then
      begin
        memo1.Lines.Add('接收数据...');//??????
        bStart:=True;
      end;
      fsRecv.WriteBuffer(bufRecv^,iLength);//
      Socket.SendText(MP_NEXTWILLBEDATA);
    end;
  finally
    FreeMem(bufRecv,iLength);
    //FreeMem(bufRecv,2000);
  end;
end;procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Clear;
  ss.Port:=2000;
  ss.Open;
end;procedure TForm1.FormDestroy(Sender: TObject);
begin
  ss.Close;
end;end.