• 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.

  • 相关阅读:
    单调队列 POJ 2823
    大组合数取mod lucas 定理
    多校4
    多校2
    2016多校1
    百度之星 初赛B续
    iot-web增加apis-namespace组件
    25.75k8s
    新项目增加gradlew
    vue图片点击放大预览v-viewer
  • 原文地址:https://www.cnblogs.com/zhangzhifeng/p/5867198.html
Copyright © 2020-2023  润新知