Delphi ServerSocket,ClientSocket示例


Delphi ServerSocket,ClientSocket示例
2008-05-09 16:20

Delphi TServerSocket,TClientSocket實現傳送文件代碼

1.建立兩個工程Server及Client

分別放TServerSocket及TClientSocket控件,Demo,Edit控件等。

2.設置TServerSocket name為 SS, ServerType為stNonBlocking,TClientSocket name為cs,ClientType為ctNonBlocking表示異步讀寫信息。注意ClientType和ServerType要相一致.若為ctBlocking則表示同步讀寫信息。(相一致,這點相當重要!香巴拉~)

3.Socket傳送文件的順序圖

a)Client-->Server MP_QUERY

b)Server-->Client MP_ACCEPT

c) Client-->Server MP_FileProperty

d)Server-->Client MP_NextWillBeData

e)Client-->Server MP_NextWillBeData

f)Server-->Client MP_DATA

g) Client-->Server 發送數據

h) Server接收數據並處理

i)Client-->Server MP_END結束

4.Client端代碼

unit UnitClient;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ScktComp, StdCtrls, Buttons, ExtCtrls, ComCtrls;
Const
//設置協議標志符
//標志將要發送文件名
MP_QUERY ='aaaaa';
//標志服務器拒絕接收
MP_REFUSE ='bbbbb';
//標志服務器同意接收文件
MP_ACCEPT ='ccccc';
//標志將要傳遞數據
MP_NEXTWILLBEDATA='ddddd';
//標志服務器端准備接收數據
MP_DATA ='eeeee';
//標志客戶端取消了本次發送操作
MP_ABORT ='fffff';
//標志已經發送完畢
MP_END='iiiii';
//標志發送的文件長度
MP_FILEPROPERTY='jjjjj';
//指定每次發送包的大小
iBYTEPERSEND=1024;

type
TForm1 = class(TForm)
    OpenDialog1: TOpenDialog;
    cs: TClientSocket;
    Panel1: TPanel;
    btnSendFile: TBitBtn;
    edtIPAddress: TEdit;
    Memo1: TMemo;
    edtHostName: TEdit;
    RB1: TRadioButton;
    RB2: TRadioButton;
    ProBar: TProgressBar;
    Btncancel: TBitBtn;
    Btnexit: TBitBtn;
    procedure btnSendFileClick(Sender: TObject);
    procedure csRead(Sender: TObject; Socket: TCustomWinSocket);
    procedure FormCreate(Sender: TObject);
    procedure BtncancelClick(Sender: TObject);
    procedure BtnexitClick(Sender: TObject);
private
    //定義一個發送文件的數據流
    fsSend: TFileStream;
    //設置開始狀態位
    tStart:Boolean;
    //標識當前時間
    TickCount:Longword;
    { Private declarations }
public
    { Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

//發送文件
procedure TForm1.btnSendFileClick(Sender: TObject);
begin
//關閉套接字連接
cs.Close;
//初始化進程條
Probar.Position:=0;
if RB1.Checked then
begin
   cs.Host:='';
   //指定要連接的主機IP地址
   cs.Address:=edtIPAddress.Text;
end
else
//指定要連接的主機名
cs.Host:=edtHostName.Text;
//要連接的主機所用端口號
cs.Port:=2000;
//打開套接字連接
cs.Open;
//點擊發送確認按鈕
if OpenDialog1.Execute then
Begin
//發送連接請求
    cs.Socket.SendText(MP_QUERY+OpenDialog1.FileName);
end;
end;

//客戶端接收來自服務器端的信息
procedure TForm1.csRead(Sender: TObject; Socket: TCustomWinSocket);
var
MsgRecv:string;
bufSend:pointer;
iLength:Integer;
begin
//得到客戶端發來的信息
MsgRecv:=Socket.ReceiveText;
//取前5位,得到協議標志符
MsgRecv:=copy(MsgRecv,1,5);
//接收到拒絕信息
if MsgRecv=MP_REFUSE then
    memo1.Lines.Add('連接請求被拒絕!')
    //接收到確認接收信息
else if MsgRecv=MP_ACCEPT then
begin
    //為要發送的文件創建文件流
    fsSend:=TFileStream.Create(OpenDialog1.FileName,fmOpenRead);
    tStart:=False;
    //進度條顯示
    Probar.Max:=fsSend.Size;
    memo1.Lines.Add('開始發送!');
    //獲取發送開始時的時間
    TickCount:=GetTickCount;
    //創建文件流並發送文件長度。
    Socket.SendText(MP_FILEPROPERTY+inttostr(Trunc(fsSend.Size/iBYTEPERSEND)+1));
end
else if MsgRecv=MP_NEXTWILLBEDATA then
begin
    //通知接收端將要傳送數據。
    Socket.SendText(MP_NEXTWILLBEDATA);
end
else if MsgRecv=MP_DATA then
begin
    //接收到確認信息,開始發送數據。
    if not tStart then
    begin
      memo1.Lines.Add('發送數據中... ...');
      tStart:=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);
        //發送長度為iLength的數據
        Socket.SendBuf(bufSend^,iLength);
         //進度條顯示
        Probar.Position:=fsSend.Position;
      finally
        //釋放內存
        FreeMem(bufSend,iLength+1);
      end;
    //發送完畢
    end else
    begin
      //通知主機文件傳送結束。
      Socket.SendText(MP_END);
      memo1.Lines.Add('發送完成!');
      //獲取發送耗時
      memo1.Lines.Add('發送耗時'+IntToStr(GetTickCount-TickCount)+'毫秒');
      fsSend.Free;    
    end;
//取消文件發送過程
end else if MsgRecv=MP_ABORT then
begin
    memo1.Lines.Add('中止!');
    //文件傳送取消
    fsSend.Free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Clear;
end;
//取消
procedure TForm1.BtncancelClick(Sender: TObject);
begin
//取消文件發送過程
cs.Socket.SendText(MP_ABORT);
end;

procedure TForm1.BtnexitClick(Sender: TObject);
begin
Form1.Close;
end;

end.
5.Server端代碼

unit UnitServer;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Buttons, ScktComp, ExtCtrls;
Const
//設置協議標志符
//標志將要發送文件名
MP_QUERY ='aaaaa';
//標志服務器拒絕接收
MP_REFUSE ='bbbbb';
//標志服務器同意接收文件
MP_ACCEPT ='ccccc';
//標志將要傳遞數據
MP_NEXTWILLBEDATA='ddddd';
//標志服務器端准備接收數據
MP_DATA ='eeeee';
//標志客戶端取消了本次發送操作
MP_ABORT ='fffff';
//標志已經發送完畢
MP_END='iiiii';
//標志發送的文件長度
MP_FILEPROPERTY='jjjjj';
//指定每次發送包的大小
iBYTEPERSEND=1024;
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;
    //設置開始狀態位
    tStart:Boolean;
    //標識當前時間
    TickCount:Longword;
    { Private declarations }
public
    { Public declarations }
end;

var
Form1: TForm1;

implementation


{$R *.DFM}
//服務器端接收來自客戶端的信息
procedure TForm1.ssClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
msgr,theFileName:string;
bufRecv:Pointer;
iLength:Integer;
begin
//接收到的數據的長度
iLength:=Socket.ReceiveLength;
//開辟一塊新的內存,用來保存接收到的數據
GetMem(bufRecv,iLength);
try
    //接收數據
    Socket.ReceiveBuf(bufRecv^,iLength);
    //將接收到的數據以字符串的形式存到msgr中
    msgr:=StrPas(PChar(bufRecv));
    //取前5個字符
    msgr:=Copy(msgr,1,5);
    if msgr=MP_QUERY then
    begin
      //去掉字符串前后的空格和控制字符
      msgr:=Trim(StrPas(PChar(bufRecv)));
      //第5個字符后面的字符串為文件名
      theFileName:=ExtractFileName(Copy(msgr,6,Length(msgr)));
      SaveDialog1.Title:='請選擇或輸入接收到的數據保存到的文件名:';
      SaveDialog1.FileName:=theFileName;
      //點擊確認保存按鈕
      if SaveDialog1.Execute then
      begin
        //為需保存的文件創建文件流
        fsRecv:=TFileStream.Create(SaveDialog1.FileName,fmCreate);
        //如果同意接收數據。
        memo1.Lines.Add ('開始接收!');
        TickCount:=GetTickCount;
        //發送同意接收文件的信息
        Socket.SendText(MP_ACCEPT);
        tStart:=False;
      end
      else
        //發送拒絕接收文件的信息
        Socket.SendText(MP_REFUSE);
    end
    else if msgr=MP_FILEPROPERTY then
    begin
      //接收文件長度並說明主機可以接收數據了
      Socket.SendText(MP_NEXTWILLBEDATA);
    end
    else if msgr=MP_NEXTWILLBEDATA then
    begin
      //要求發送端發送數據
      Socket.SendText(MP_DATA);
    end else if msgr=MP_END then
    begin
      memo1.Lines.Add ('文件傳送完成!');
      memo1.Lines.Add ('接收耗時'+IntToStr(GetTickCount-TickCount)+'毫秒');
      fsRecv.Free;
    end
    //接收到文件傳送取消信息
    else if msgr=MP_ABORT then    
    begin
      memo1.Lines.Add ('MP_ABORT');
      Socket.SendText(MP_ABORT);
      fsRecv.Free;
    end
   else
    begin
      if not tStart then
      begin
        memo1.Lines.Add('接收數據...');
        tStart:=True;
      end;
      //將接收緩沖區數據寫入文件
      fsRecv.WriteBuffer(bufRecv^,iLength);
      //通知客戶端繼續發送數據
      Socket.SendText(MP_DATA);
    end;
finally
    //釋放內存
    FreeMem(bufRecv,iLength);
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.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM