• delphi的Socket(有两种分别继承TObject和TComponent的方式)


    在Delphi中,对于Windows中的Socket进行了有效的封装。在Delphi中,按其继承关系,可以分层两类:
    一、TComponent--TAbstractSocket--TCustomSocket--TCustomServerSocket--TServerSocket
    TComponent--TAbstractSocket--TCustomSocket--TClientSocket
    二、直接从TObject继承过来:
    TObject--TCustomWinSocket--TServerWinSocket
    TObject--TCustomWinSocket--TClientWinSocket

    TObject--TCustomWinSocket--TServerClientWinSocket

    可以看出第一类建立在TCustomSocket基础上,第二类建立在TCustomWinSocket的基础上。第一类建立在TComponet的基 础上,第二类直接构建在TObject基础上。因此如果用户非常熟悉Socket并且想要编写控制台程序时,可以使用TCustomWinScoket 类。同uses中可以看出,它们都在ScktComp.pas中实现,而在schtComp.pas中,则包含了winsock.pas文件,如果继续深入winsock文件,在其中可以发现所有的Windows Socket的基本方法。

    在网络编程中,WinSocket API编程是最基本,也是最麻烦的地方(说句不怕影响形象的话,我对此就是一知半解)。但是,如果你是使用C++Builder作为编程平台,你就偷着乐吧,有了BCB,菜鸟变高手!:-)

    在BCB中,TServerSocket和TClientSocket涵盖了基本的WinSocket编程,其中TServerSocket作为服务器方使用,TClientSocket作为客户端使用,这两个组件本身并不提供Socket连接,但是他们都有一个Socket属性,这个属性才提供了 Socket连接。下面就先向大家介绍一下这两个组件常用的方法属性,然后在通过一个例子来看看这两个组件的使用。

    1)TServerSocket 名称 类型 说明 
    Socket TServerWinSocket 最重要的属性,提供Socket连接,事实上发送/接收数据都要靠这个属性,下面还有详细的介绍。 
    Port int 要监听的端口,如果在Service属性中指定了服务类型,此属性将被忽略。 
    Service AnsiString 提供的服务,如HTTP、FTP等,如果在这里指定了服务类型,Port将被忽略,因为各种服务都有特定的端口,如FTP:21、HTTP:80 
    ServerType TServerType 设置与客户连接的方式,取值为两个枚举常量stNonBlocking和 stThreadBlocking,stNonBlocking表示用非阻塞方式连接每一个客户,每个连接都在一个单独的线程中处理。并用 OnClientRead()和OnClientWrite()通知服务器端的Socker进行读写。 stThreadBlocking表示以阻塞方式连接客户,即以主动查询的方式可客户连接。 
    Active bool 激活服务,相当于调用Open()方法。 
    OnAccept 事件 当有客户请求连接时触发 
    OnClientRead 事件 通知服务器去读取有关信息。OnClientWrite与此类似。

    2)TClientSocket 名称 类型 说明 

    Socket TClientWinSocket 同TServerSocket 
    Active bool 同TServerSocket 
    Address AnsiString 服务器的IP地址,如202.98.35.14 
    ClientType TClientType 与服务器连接方式,取值为两个枚举常量ctNonBlocking,tBlocking。ctNonBlocking表示非阻塞方式,ctBlocking表示阻塞方式,详见上例。 
    Host AnsiString 要连接的主机名,如www.cpcw.com 
    Port int 同TServerSocket 
    Service AnsiString 同TServerSocket 
    OnConnect 事件 当连接时发生,OnConnecting、OnDisConnect与此类似 
    OnRead 事件 通知客户机去读取有关信息。OnWrite与此类似。

    TServerSocket和TClientSocket只提供基本的服务器/客户机的连接,真正提供数据传输的是它们都有的属性Socket,它的类型分别是TServerWinSocket和TClientWinSocket,而TServerWinSocket和 TClientWinSocket的父类都是TCustomWinSocket,下面我们就来看看TServerWinSocket和 TClientWinSocket常用的属性和方法。

    共同的属性方法(来源于TCustomWinSocket)

    名称 类型 说明 
    Connected bool 检查是否连接成功 
    LocalAddress AnsiString 本地IP地址,与此类似LocalHost:本机域名,LocalPort:本机端口 
    RemoteAddress AnsiString 另一端的IP地址,与此类似RemoteHost:另一端域名,RemotePort:另一端端口 
    SocketHandle int 只读,返回Socket对象的Windows句柄,如果你要调用WinSocket API函数,将用到此句柄。 
    Handle HWND Socket能够接受到的异步事件都是以Windows消息的形式发送给此句柄的。 
    Close() 方法 作为服务器,关闭所有连接;作为客户机,关闭自己与服务器的连接 
    SendText(AnsiString) 方法 发送一个字符串 
    SendBuf(void* buff,int count) 发送缓冲区buff中的count个字节,返回实际发送的字节数 
    SendStream(TStream* AStream) 发送一个流到Socket中。 
    ReceiveText() 从Socket中读取并返回一个字符串。 
    ReceiveLength() 从Socket读取数据需多少字节的缓冲区。 
    ReceiveBuf(void* buff,int count) 从Socket中读取count字节的数据到buff。

    TClientWinSocket

    TClientWinSocket只增加了一个ClientType属性,用于决定与服务器的连接类型(参见TClientSocket->ClientType)。

    TServerWinSocket

    名称 类型 说明 
    ServerType   服务类型,参见TServerSocket->ServerType 
    ActiveConnection int 只读,返回当前活动的连接数 
    Connection TCustomWinSocket 数组,索引n表示第n+1个连接,如Connection[0]表示第一个连接

    有了这些知识,我们就可以完成一些基本的WinSocket编程了,下面就结合一个简单的闲聊程序来看看具体的应用。

    首先在窗体上放置以下VCL组件,并修改相应属性:

    类型 Name属性 Caption/Text 说明 
    TCheckBox ckListen 监听 当选取时,本程序作为服务器 
    TCheckBox ckConnect 连接 当选取时,本程序作为客户机 
    TEdit edName 无名氏 闲聊时所用的名字 
    TBitBtn bbtSave &S保存 单击时保存谈话内容 
    TBitBtn bbtClose &C关闭 单击时关闭此窗口(设置Kind=bkClose) 
    TEdit edTalk   在此输入谈话内容 
    TMemo mmTalk   在此显示谈话内容 
    TServerSocket ServerSocket1   作服务器时使用(设置Port=2222) 
    TClientSocket ClientSocket1   作为客户时使用(设置Port=2222) 
    TSaveDialog sdTalk   保存文件时的选项(设置DefaultExt="*.txt",Filter=文本文件(*.TXT)|*.txt|所有文件(*.*)|*.*)。 
    TStatusBar StatusBar1   用于显示一些提示信息,只要在属性"Pannels"中加一栏即可

    程序作为服务器的设置:
    当单击"监听"时,如果没有监听则开始监听,在提示栏中显示"监听",并把"连接"这个复选框无效。如果已经监听,则取消监听,并使"连接"这个复选框有效。所以,在ckListen的OnClick事件中加入以下代码:
    if(ServerSocket1->Active)
    {
    ServerSocket1->Active=false;
    ckListen->Checked=false;
    StatusBar1->Panels->Items[0]->Text="";
    }
    else
    {
    ServerSocket1->Active=true;
    ckListen->Checked=true;
    ClientSocket1->Active=false;
    StatusBar1->Panels->Items[0]->Text="监听..." ;
    }
    ckConnect->Enabled=!(ckListen->Checked);
    当有客户加入时,向所有的客户发出通知:并在自已的mmTalk加入此消息:所以在ServerSocket1的OnAccept事件中加入如下代码:
    int i;
    AnsiString str1="服务器消息:"+Socket->RemoteHost+"加入";
    for(i=0;i<ServerSocket1->Socket->ActiveConnections;i++)
    ServerSocket1->Socket->Connections[i]->SendText("服务器消息:"+Socket->RemoteHost+"加入");
    StatusBar1->Panels->Items[0]->Text=str1;
    mmTalk->Lines->Add(str1);
    当客户机通知服务器读信息时,首先读出字符串,然后把读到的字符串发送到每一台连接的客户,并在自已的mmTalk中加入客户发送来的字符串。所以,在TServerSocket的OnClientRead事件中加入以下代码:
    AnsiString str1=Socket->ReceiveText();
    mmTalk->Lines->Add(str1);
    int i;

    for(i=0;i<ServerSocket1->Socket->ActiveConnections;i++)

    ServerSocket1->Socket->Connections[i]->SendText(str1);
    程序作为客户机的设置:
    当单击"连接"时,如果还未连接,则询问要连接的主机,然后连接之,屏蔽"监听";如果已经连接,则断开连接。"监听"使能。所以,在ckConnect的OnClick事件中加入以下代码:
    if(ClientSocket1->Active)
    {
    ClientSocket1->Active=false;
    ckConnect->Checked =false;
    }
    else
    {
    AnsiString Server="localhost";
    if(InputQuery("连接","请输入要连接的主机地址:",Server))
    {
    ClientSocket1->Host=Server;
    ClientSocket1->Active=true;
    ckConnect->Checked =true;
    }
    }
    ckListen->Enabled= !(ckConnect->Checked);

    当连接服务器成功时,在状态栏中显示此信息,所以,在ClientSocket1的ClientSocket1Connect中加入:
    StatusBar1->Panels->Items[0]->Text ="连接到主机:"+Socket->RemoteHost;
    当服务器发送字符串来时,把它加入mmTalk中,但如果本字符串就是自已发送的(因为服务器会把收到的消息发给每一客户),为条信息就是重复的,所以,要比较mmTalk中最后两条信息是否相同,如果相同,则删除重复信息。代码如下:
    mmTalk->Lines->Add(Socket->ReceiveText());
    int i=mmTalk->Lines->Count-1;
    if(mmTalk->Lines->Strings[i]==mmTalk->Lines->Strings[i-1])
    mmTalk->Lines->Delete(i);
    公用部分
    当在edTalk输入交谈内容,按回车键表示输入完成,此时把交谈内容发送出去并清除edTalk的内容。在发送信息时,要看本程序是作为服务器还是客户机,如果是服务器则把信息发送到每一个客户;如果是作为客户则把信息发送到服务器。代码如下:
    if(Key==13)
    {
    mmTalk->Lines->Add(edName->Text+":"+edTalk->Text);
    if(ckListen->Enabled&&ckConnect->Enabled==false)
    //"监听"有效,"连接"无效。表示是服务器
    {
    int i;
    for(i=0;i<ServerSocket1->Socket->ActiveConnections;i++)
    ServerSocket1->Socket->Connections[i]->SendText(edName->Text+":"+edTalk->Text);
    }
    else
    {
    ClientSocket1->Socket->SendText(edName->Text+":"+edTalk->Text);
    }
    edTalk->Text="";
    }

    mmTalk的内容不可能永远增加,所以当它有100行时就清空它,在mmTalk的OnChange事件中检查:
    if(mmTalk->Lines->Count>=100)mmTalk->Lines->Clear(); 
    当然你也可以双击mmTalk来清空它,在mmTalk的OnDblClick事件中加入
    mmTalk->Lines->Clear();
    当你觉得谈话的内容很有意思,你可以单击bbtSave打开保存对话框设置保存特性,所以在bbtSave的onClick中加入代码:
    if(sdTalk->Execute())
    mmTalk->Lines->SaveToFile(sdTalk->FileName);
    OK,我们的闲聊程序就完成了,在局域网中试试吧?如果你只有一台机器,客户程序在连接时服务器时输入localhost或你机器的名字就可以了。

    http://blog.csdn.net/s371795639/article/details/53976573

  • 相关阅读:
    疫情在家没事做推荐个学习的目录:怎么从一名码农成为架构师的必看知识点:目录大全(不定期更新)
    教你使用 Swoole-Tracker 秒级定位 PHP 卡死问题
    怎样深入学习php,成为php高手!?
    PHP实现简单RPC
    PHP工作岗位要求
    关于PHP在企业级开发领域的访谈
    未知及待办清单
    siege报告学习
    session&token based auth登录方式描述
    学习JWT
  • 原文地址:https://www.cnblogs.com/findumars/p/6323507.html
Copyright © 2020-2023  润新知