⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c++builder网络编程系列讲座第一讲:tserversocket和tclientsocket的使用.txt

📁 C&C++论坛精华
💻 TXT
字号:
作者:hxfwsk
email: hxfwsk@hotmail.com
日期:6/15/2001 7:28:35 PM

TServerSocket和TClientSocket的使用 [H5]C++Builder网络编程系列之一[/H5][H4]TServerSocket和TClientSocket的使用[/H4]
在网络编程中,WinSocket API编程是最基本,也是最麻烦的地方(说句不怕影响形象的话,我对此就是一知半解)。但是,如果你是使用C++Builder作为编程平台,你就偷着乐吧,有了BCB,菜鸟变高手!:-)
在BCB中,TServerSocket和TClientSocket涵盖了基本的WinSocket编程,其中TServerSocket作为服务器方使用,TClientSocket作为客户端使用,这两个组件本身并不提供Socket连接,但是他们都有一个Socket属性,这个属性才提供了Socket连接。下面就先向大家介绍一下这两个组件常用的方法属性,然后在通过一个例子来看看这两个组件的使用。[H5]1)TServerSocket[/H5][TABLE][TR][TD]名称[/TD][TD]类型[/TD][TD]说明[/TD][/TR][TR][TD]Socket[/TD][TD]TServerWinSocket[/TD][TD]最重要的属性,提供Socket连接,事实上发送/接收数据都要靠这个属性,下面还有详细的介绍。[/TD][/TR][TR][TD]Port[/TD][TD]int[/TD][TD]要监听的端口,如果在Service属性中指定了服务类型,此属性将被忽略。[/TD][/TR][TR][TD]Service[/TD][TD]AnsiString[/TD][TD]提供的服务,如HTTP、FTP等,如果在这里指定了服务类型,Port将被忽略,因为各种服务都有特定的端口,如FTP:21、HTTP:80[/TD][/TR][TR][TD]ServerType[/TD][TD]TServerType[/TD][TD]设置与客户连接的方式,取值为两个枚举常量stNonBlocking和 stThreadBlocking,stNonBlocking表示用非阻塞方式连接每一个客户,每个连接都在一个单独的线程中处理。并用OnClientRead()和OnClientWrite()通知服务器端的Socker进行读写。 stThreadBlocking表示以阻塞方式连接客户,即以主动查询的方式可客户连接。[/TD][/TR][TR][TD]Active[/TD][TD]bool[/TD][TD]激活服务,相当于调用Open()方法。[/TD][/TR][TR][TD]OnAccept[/TD][TD]事件[/TD][TD]当有客户请求连接时触发[/TD][/TR][TR][TD]OnClientRead[/TD][TD]事件[/TD][TD]通知服务器去读取有关信息。OnClientWrite与此类似。[/TD][/TR][/TABLE][H5]2)TClientSocket[/H5][TABLE][TR][TD]名称[/TD][TD]类型[/TD][TD]说明[/TD][/TR][TR][TD]Socket[/TD][TD]TClientWinSocket[/TD][TD]同TServerSocket[/TD][/TR][TR][TD]Active[/TD][TD]bool[/TD][TD]同TServerSocket[/TD][/TR][TR][TD]Address[/TD][TD]AnsiString[/TD][TD]服务器的IP地址,如202.98.35.14[/TD][/TR][TR][TD]ClientType[/TD][TD]TClientType[/TD][TD]与服务器连接方式,取值为两个枚举常量ctNonBlocking,tBlocking。ctNonBlocking表示非阻塞方式,ctBlocking表示阻塞方式,详见上例。[/TD][/TR][TR][TD]Host[/TD][TD]AnsiString[/TD][TD]要连接的主机名,如www.cpcw.com[/TD][/TR][TR][TD]Port[/TD][TD]int[/TD][TD]同TServerSocket[/TD][/TR][TR][TD]Service[/TD][TD]AnsiString[/TD][TD]同TServerSocket[/TD][/TR][TR][TD]OnConnect[/TD][TD]事件[/TD][TD]当连接时发生,OnConnecting、OnDisConnect与此类似[/TD][/TR][TR][TD]OnRead[/TD][TD]事件[/TD][TD]通知客户机去读取有关信息。OnWrite与此类似。[/TD][/TR][/TABLE]
TServerSocket和TClientSocket只提供基本的服务器/客户机的连接,真正提供数据传输的是它们都有的属性Socket,它的类型分别是TServerWinSocket和TClientWinSocket,而TServerWinSocket和TClientWinSocket的父类都是TCustomWinSocket,下面我们就来看看TServerWinSocket和TClientWinSocket常用的属性和方法。[H5]●共同的属性方法(来源于TCustomWinSocket)[/H5][TABLE][TR][TD]名称[/TD][TD]类型[/TD][TD]说明[/TD][/TR][TR][TD]Connected[/TD][TD]bool[/TD][TD]检查是否连接成功[/TD][/TR][TR][TD]LocalAddress[/TD][TD]AnsiString[/TD][TD]本地IP地址,与此类似LocalHost:本机域名,LocalPort:本机端口[/TD][/TR][TR][TD]RemoteAddress[/TD][TD]AnsiString[/TD][TD]另一端的IP地址,与此类似RemoteHost:另一端域名,RemotePort:另一端端口[/TD][/TR][TR][TD]SocketHandle[/TD][TD]int[/TD][TD]只读,返回Socket对象的Windows句柄,如果你要调用WinSocket API函数,将用到此句柄。[/TD][/TR][TR][TD]Handle[/TD][TD]HWND[/TD][TD]Socket能够接受到的异步事件都是以Windows消息的形式发送给此句柄的。[/TD][/TR][TR][TD]Close()[/TD][TD]方法[/TD][TD]作为服务器,关闭所有连接;作为客户机,关闭自己与服务器的连接[/TD][/TR][TR][TD]SendText(AnsiString)[/TD][TD]方法[/TD][TD]发送一个字符串,[/TD][/TR][TR][TD]SendBuf(void* buff,int count)[/TD][TD]发送缓冲区buff中的count个字节,返回实际发送的字节数[/TD][/TR][TR][TD]SendStream(TStream* AStream)[/TD][TD]发送一个流到Socket中。[/TD][/TR][TR][TD]ReceiveText()[/TD][TD]从Socket中读取并返回一个字符串。[/TD][/TR][TR][TD]ReceiveLength()[/TD][TD]从Socket读取数据需多少字节的缓冲区。[/TD][/TR][TR][TD]ReceiveBuf(void* buff,int count)[/TD][TD]从Socket中读取count字节的数据到buff。[/TD][/TR][/TABLE][H5]●TClientWinSocket[/H5]
TClientWinSocket只增加了一个ClientType属性,用于决定与服务器的连接类型(参见
TClientSocket->ClientType)。[H5]●TServerWinSocket[/H5][TABLE][TR][TD]名称[/TD][TD]类型[/TD][TD]说明[/TD][/TR][TR][TD]ServerType[/TD][TD]?/td> [TD]服务类型,参见TServerSocket->ServerType。[/TD][/TR][TR][TD]ActiveConnection[/TD][TD]int[/TD][TD]只读,返回当前活动的连接数。[/TD][/TR][TR][TD]Connection[/TD][TD]TCustomWinSocket[/TD][TD]数组,索引n表示第n+1个连接,如Connection[0]表示第一个连接。[/TD][/TR][/TABLE]
有了这些知识,我们就可以完成一些基本的WinSocket编程了,下面就结合一个简单的闲聊程序来看看具体的应用。
首先在窗体上放置以下VCL组件,并修改相应属性:[TABLE][TR][TD]类型[/TD][TD]Name属性[/TD][TD]Caption/Text[/TD][TD]说明[/TD][/TR][TR][TD]TCheckBox[/TD][TD]ckListen[/TD][TD]监听[/TD][TD]当选取时,本程序作为服务器[/TD][/TR][TR][TD]TCheckBox[/TD][TD]ckConnect[/TD][TD]连接[/TD][TD]当选取时,本程序作为客户机[/TD][/TR][TR][TD]TEdit[/TD][TD]edName[/TD][TD]无名氏[/TD][TD]闲聊时所用的名字。[/TD][/TR][TR][TD]TBitBtn[/TD][TD]bbtSave[/TD][TD]&S保存[/TD][TD]单击时保存谈话内容[/TD][/TR][TR][TD]TBitBtn[/TD][TD]bbtClose[/TD][TD]&C关闭[/TD][TD]单击时关闭此窗口(设置Kind=bkClose)[/TD][/TR][TR][TD]TEdit[/TD][TD]edTalk[/TD][TD]?/td> [TD]在此输入谈话内容[/TD][/TR][TR][TD]TMemo[/TD][TD]mmTalk[/TD][TD]?/td> [TD]在此显示谈话内容[/TD][/TR][TR][TD]TServerSocket[/TD][TD]ServerSocket1[/TD][TD]?/td> [TD]作服务器时使用(设置Port=2222)[/TD][/TR][TR][TD]TClientSocket[/TD][TD]ClientSocket1[/TD][TD]?/td> [TD]作为客户时使用(设置Port=2222)[/TD][/TR][TR][TD]TSaveDialog[/TD][TD]sdTalk[/TD][TD]?/td> [TD]保存文件时的选项(设置DefaultExt="*.txt",Filter=文本文件(*.TXT)|*.txt|所有文件(*.*)|*.*)。[/TD][/TR][TR][TD]TStatusBar[/TD][TD]StatusBar1[/TD][TD]?/td> [TD]用于显示一些提示信息,只要在属性"Pannels"中加一栏即可[/TD][/TR][/TABLE]
然后调整布局如下图所示:
http://go.163.com/~cbuilder/use/27_0.gif[H5]程序作为服务器的设置:[/H5]
当单击"监听"时,如果没有监听则开始监听,在提示栏中显示"监听",并把"连接"这个复选框无效。如果已经监听,则取消监听,并使"连接"这个复选框有效。所以,在ckListen的on_click事件中加入以下代码:[PRE] 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事件中加入如下代码:[/PRE][PRE] int i; AnsiString str1="服务器消息:"+Socket->RemoteHost+"加入"; for(i=0;iSocket->ActiveConnections;i++) ServerSocket1->Socket->Connections[i]->SendText("服务器消息:"+Socket->RemoteHost+"加入"); StatusBar1->Panels->Items[0]->Text=str1; mmTalk->Lines->Add(str1); 
当客户机通知服务器读信息时,首先读出字符串,然后把读到的字符串发送到每一台连接的客户,并在自已的mmTalk中加入客户发送来的字符串。所以,在TServerSocket的OnClientRead事件中加入以下代码:[/PRE][PRE] AnsiString str1=Socket->ReceiveText(); mmTalk->Lines->Add(str1); int i; for(i=0;iSocket->ActiveConnections;i++) ServerSocket1->Socket->Connections[i]->SendText(str1); [/PRE][H5]程序作为客户机的设置:[/H5][PRE]
当单击"连接"时,如果还未连接,则询问要连接的主机,然后连接之,屏蔽"监听";如果已经连接,则断开连接。"监听"使能。所以,在ckConnect的on_click事件中加入以下代码: [/PRE][PRE] 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中加入:[/PRE][PRE] StatusBar1->Panels->Items[0]->Text ="连接到主机:"+Socket->RemoteHost;
 当服务器发送字符串来时,把它加入mmTalk中,但如果本字符串就是自已发送的(因为服务器会把收到的消息发给每一客户),为条信息就是重复的,所以,要比较mmTalk中最后两条信息是否相同,如果相同,则删除重复信息。代码如下:[/PRE][PRE] 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); [/PRE][H5]公用部分[/H5][PRE]
当在edTalk输入交谈内容,按回车键表示输入完成,此时把交谈内容发送出去并清除edTalk的内容。在发送信息时,要看本程序是作为服务器还是客户机,如果是服务器则把信息发送到每一个客户;如果是作为客户则把信息发送到服务器。代码如下:[/PRE][PRE] if(Key==13) { mmTalk->Lines->Add(edName->Text+":"+edTalk->Text); if(ckListen->Enabled&&ckConnect->Enabled==false) //"监听"有效,"连接"无效。表示是服务器 { int i; for(i=0;iSocket->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事件中检查:[/PRE][PRE] if(mmTalk->Lines->Count>=100)mmTalk->Lines->Clear();
当然你也可以双击mmTalk来清空它,在mmTalk的OnDblClick事件中加入:[/PRE][PRE] mmTalk->Lines->Clear();
当你觉得谈话的内容很有意思,你可以单击bbtSave打开保存对话框设置保存特性,所以在bbtSave的on_click中加入代码:[/PRE][PRE] if(sdTalk->Execute()) mmTalk->Lines->SaveToFile(sdTalk->FileName);
OK,我们的闲聊程序就完成了[/PRE]

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -