(摘自)http://hi.baidu.com/kvkens/blog/item/a7b6ca176b79c80cc93d6d18.html
一直想学习一下网络编程,苦于无法找到相关的资料,以前也写过一些网络程序,但那些都是用Indy的控件,使用起来相对较为简单,无法接触到底层的东西。最近安装了VISTA操作系统后,发现该系统彻底的不支持Delphi 7了。在网上下载了Delphi 2006 Lite版,少了很多控件,其中就包括了以前用的Indy控件,但幸运的是可以使用TTcpServer和TTcpClient控件。但这个控件基本上不会使用,在网上查找相关的资料也相当的困难,论坛中基本上是问这个控件怎么使用的,回答的也多是一些错的。另外该死的VISTA系统也不支以前的老的帮助,幸运的是该控件带有源代码,经过几天的研究。终于了解了该控件的使用方法。下面介绍一下该控件的使用方法以及相关的注意事项。
这个控件的属性不多,其他的属性没什么好介绍的,都可以顾名思义的设就形了,需要一提的是BlockMode,本文着重介绍当BlockMode为bmBlocking的使用方法。这种阻塞模式为线程阻塞,其实也就是阻塞模式,当调用Open的方法后,系统自动会开启一个线程来监控是否有客户端连接。如果有客户端的连接过来后,系统会自动为每个客户端提供一个线程。这个线程会有一个默认线程类来实现的,但该类基本上没有什么功能,如果想使用TTcpServer这个类的话,那么这个类的代码是必须要重写的。
客户端线程类的写法:
TServerThread=class(TClientSocketThread)
private
s:string;
protected
procedure SyncProc;override;
end;
{ TServerThread }
procedure TServerThread.SyncProc;
begin
form1.Memo1.Lines.Add(formatdatetime('mm-dd hh:mm:ss :',now)+s);
end;
该控件提供的事件也不是很多,需要注意使用的有两个,一个是OnGetThread,另外一个是OnAccept。只要在这两个里面进行编码就基本上就可以使用这个类了。OnGetThread里面需要写的代码是用自己的线程类来替换掉默认的主线程类。OnAccept里面需要写的代码是主线程类中需要处理的任务,如读取客户端的消息,向客户端回应等。需要注意的是OnAccept的代码是在线程中运行,需要写成死循环,除非到该客户端中止为止,并且还需要不停的去检查该线程是否中止。另外如果访问主线程中的资源,需要进行同步处理。以下是这个两个方法的代码示例:
1、OnGetThread中取代线程的代码
procedure TForm1.TcpServer1GetThread(Sender: TObject;
var ClientSocketThread: TClientSocketThread);
begin
ClientSocketThread:=TServerThread.Create(tcpserver1.ServerSocketThread);
end;
2、OnAccept中的代码
procedure TForm1.TcpServer1Accept(Sender: TObject;
ClientSocket: TCustomIpClient);
var T:TServerThread;
begin
T:=TServerThread(ClientSocket.GetThreadObject);
T.s :=clientsocket.RemoteHost +'已连接';
t.SyncProc
while not T.Terminated and clientsocket.Connected do
begin
if ClientSocket.WaitForData(0) then
begin
t.s:=ClientSocket.Receiveln();
ClientSocket.Sendln('Re:'+t.s);
if t.s='QUIT' then ClientSocket.Disconnect
else T.SyncProc;
end;
end;
t.s :=clientsocket.RemoteHost +'已断开';
t.SyncProc
end;
以上的代码写好后,该控件就可以正常工作了。这个程序的功能比较简单,客户发过来消息后,自动回应客户一条信息。如果收到客户退出的消息后,就会自动退出线程,并中止与客户端的连接。
总而言之,这个控件封装的还是不错的,只需要简单的和行代码就可以实现复杂的服务器程序。下面是这个程序完整的例子:
unit Unit1;
{
项目: TTcpServer 示例程序
作者: 黄涛
创建: 2008-4-25
}
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Sockets, StdCtrls;
type
TForm1 = class(TForm)
btStart: TButton; //开始终止按钮
Server: TTcpServer; //服务器控件
mmLog: TMemo; //日志控件
procedure ServerGetThread(Sender: TObject; //获取线程的事件
var ClientSocketThread: TClientSocketThread);
//客户端连接事件
procedure ServerAccept(Sender: TObject; ClientSocket: TCustomIpClient);
procedure btStartClick(Sender: TObject); //点击启动中止事件
procedure AddLog(msg:String);//添加日志
private
{ Private declarations }
public
{ Public declarations }
end;
TServerThread=class(TClientSocketThread) //客户端线程
private
s:string;
protected
procedure SyncProc;override; //同步的方法
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.AddLog(msg: String); //添加日志
begin
mmLog.Lines.Add(formatdatetime('mm-dd hh:mm:ss :',now)+msg);
end;
procedure TForm1.btStartClick(Sender: TObject);
begin
if server.Active then Server.close
else Server.Open
if Server.Active then
begin
btStart.Caption :='停止'
AddLog('服务器已启动')
end
else
begin
btStart.Caption :='启动';
AddLog('服务器已停止');
end;
end;
procedure TForm1.ServerAccept(Sender: TObject;
ClientSocket: TCustomIpClient);
var T:TServerThread;
begin
T:=TServerThread(ClientSocket.GetThreadObject); //获取该线程的对象句柄
T.s :=clientsocket.RemoteHost +'已连接';
T.ExecuteSyncProc; //添加已连接的日志
while not T.Terminated and clientsocket.Connected do
begin //该线程未中止和客户端未中止连接时执行
if ClientSocket.WaitForData(0) then
begin //如果客户端发送数据
t.s:=ClientSocket.Receiveln(); //接收数据
ClientSocket.Sendln('Re:'+t.s); //回复客户端
if t.s='QUIT' then ClientSocket.Disconnect //如果是退出指令,则断开连接
else T.SyncProc; //否则添加日志
end;
end;
t.s :=clientsocket.RemoteHost +'已断开'; //添加断开客户端的日志
T.ExecuteSyncProc;
end;
procedure TForm1.ServerGetThread(Sender: TObject;
var ClientSocketThread: TClientSocketThread);
begin //用自己的线程取代标准的端线程
ClientSocketThread:=TServerThread.Create(Server.ServerSocketThread);
end;
{ TServerThread }
procedure TServerThread.SyncProc;
begin
Form1.AddLog(s); //添加日志
end;
end.