在网络编程中,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:2一、HTTP:80
ServerType TServerType 设置与客户链接的方式,取值为两个枚举常量stNonBlocking和
stThreadBlocking,stNonBlocking表示用非阻塞方式链接每个客户
每一个链接都在一个单独的线程中处理。并用OnClientRead()和
OnClientWrite()通知服务器端的Socker进行读写。stThreadBlocking
表示以阻塞方式链接客户,即以主动查询的方式可客户链接。
Active bool 激活服务,至关于调用Open()方法。
OnAccept事件当有客户请求链接时触发
OnClientRead事件通知服务器去读取有关信息。OnClientWrite与此相似。
2)TClientSocket
名称 类型 说明
Socket TClientWinSocket 最重要的属性,提供Socket链接,事实上发送/接收数据都要靠这个属性.
Active bool 激活服务,至关于调用Open()方法。
Address AnsiString 服务器的IP地址,如202.98.35.14
ClientType TClientType 与服务器链接方式,取值为两个枚举常量ctNonBlocking,tBlocking。
ctNonBlocking表示非阻塞方式,ctBlocking表示阻塞方式,详见上例。
Host AnsiString 要链接的主机名,如www.cpcw.com
Port int 要监听的端口,TClientSocket,此属性将被忽略.
Service AnsiString 提供的服务,如HTTP、FTP等,若是在这里指定了服务类型,
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或你机器的名字就能够了