Y
yanliangjr9702
Unregistered / Unconfirmed
GUEST, unregistred user!
现在有一个服务器端,多个客户端。每个客户端每过30秒向服务器提交一次数据。服务器收
到数据后先分析数据然后再将数据写到数据库中。在整个过程进行的同时还要把数据库中的
数据显示出来,每隔1分钟刷新一次数据库。
我的总体思路是用多线程完成,其中显示数据部分用一个线程,其他部分(客户和服务器的
连接,服务器接收客户提交的数据,把数据写到数据库中去)用多个线程。现在有如下的问
题:
1.我作过这样的实验,用API函数来设计线程。我的程序如下:
(数据表名称:text,字段有两个:Ip和ReceText,分别用来储存接收信息的来源IP和起内容)。
function ThreadProc(Var receive:string,Var IpStr:string):LongInt;Stdcall;
begin
query1.close;
query1.sql.clear;
query1.sql.add('insert into text (Ip,ReceText)');
query1.sql.add('values("'+receive+'","'+IpStr+'")');
query1.execusql;
end;
在ServerSocket1的OnClientRead()事件中添加调用这个函数的程序:
Rece:=Socket.ReceiveText;
IpStr:=Socket.RemoteAddress;
try
Hthread1:=CreateThread(nil,0,@ThreadProc(Rece,IpStr),0,nil,ThreadID);
Finally
If (Hthread1=0) then
ShowMessage('创建线程失败!');
end;
我写这个线程的用意很简单,就是当服务器来一个客户的提交时产生一个线程,然后再在这
个线程中完成写数据库的操作。但是,在运行时产生了"Variable
required "样的错误。我现在的疑问是:
1.当用API函数产生线程时,如何传递参数?(在显示数据时由于不需要传递参数,就可以用API函数)。
2.我的这个思路对不对?如果不对,清问为什么?
(服务器的服务类型时"非阻塞")。
2.于上述方法不行,我就改用下面的方法。这是在《Delphi 4.0核心编程》中的一个例子,
我改编了一下,显示用API函数写的线程,而写操作用了一个其中的类。代码如下:
//定义的类:
TQueryThread=class (TThread)
private
FSession:TSession;
FQuery:TQuery;
FDataSource:TDataSource;
FQueryException:Exception;
procedure connectDatasource;
procedure ShowqueryError;
protected
procedure execute;override;
public
constructor create(Session:Tsession;
query:Tquery;
datasource:Tdatasource);virtual;
end;
//类的实现:
constructor TqueryThread.create(Session:Tsession;query:Tquery;datasource:Tdatasource);
begin
inherited create(true);
Fquery:=query;
Fdatasource:=datasource;
FreeOnterminate:=true;
resume;
end;
procedure TqueryThread.execute;
begin
try
FQuery.Open;
synchronize(connectdatasource);
except
Fqueryexception:=Exceptobject as exception;
synchronize(showqueryError);
showmessage('发生错误1!');
end;
end;
procedure TqueryThread.connectDatasource;
begin
FdataSource.DataSet:=fquery;
end;
procedure TqueryThread.ShowqueryError;
begin
application.ShowException(Fqueryexception);
ShowMessage('发生错误2!');
end;
procedure Runbackgroundquery(session:Tsession;query:Tquery;datasource:Tdatasource);
begin
Tquerythread.create(Session,query,datasource);
end;
{$R *.DFM}
procedure TForm1.Timer1Timer(Sender: TObject);
var //每隔1秒钟重新访问一次数据库.
i,j:integer;
begin
query1.close;
query1.sql.Clear;
query1.sql.add('select * from test');
query1.open;
runbackgroundquery(session1,query1,datasource1);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
//创建时打开ServerSocket
serversocket1.open;
end;
procedure TForm1.ServerSocket1Accept(Sender: TObject;
Socket: TCustomWinSocket);//如果客户端连接成功,则调用此过程.
begin
showmessage('连接成功!');
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);//当有一个客户端提交数据时,调用这个过程.
Var //然后产生一个线程,将数据写入数据库.
Rece,IpStr:string;
begin
Rece:=socket.ReceiveText;
IpStr:=socket.remoteaddress;
query1.close;
query1.sql.Clear;
query1.sql.add('insert into test (Ip,text)');
query1.sql.add('values("'+IpStr+'","'+Rece+'")');
query1.ExecSQL;
Runbackgroundquery(session1,query1,datasource1);
end;
此刻运行正常,向数据库中写数据也正常。但是,每接收一次数据就产生一次"Error creating curor handle "的错误。这是为什么?
后来我把客户端的程序改了一下,在OnWrite()事件中把socket.sendtext()该为:
while not falsedo
begin
sleep(10);
socket.sendtext();
end;
即每过0.01秒把数据循环发一次.但在服务器端接收时却把这些按不同的包发过来的数据
当成一个包处理了:把所有数据写到一条记录中去了!于是我就想到是不是由于相临两次发
送的包之间的间隔太短,才使得服务器认为这是一个数据包?(事实证明的确是这样.后来我
把时间间隔改了一下,改成1秒后,服务器又可认出不同的包了).那么会不会产生这样的情
况:两个来自不同客户端的数据包在同时到达服务器时被服务器认为是同一个包或者是只
能处理一个而将其中一个包丢弃掉?
3. 后来我又看到有的资料上介绍类似于我这个问题的解决办法是用"阻塞线程"解决.但是,
如何用"阻塞线程"解决这个问题?当一个客户端连接到服务器时,服务器如何判断的出此
时已经有一个客户连接?服务器又如何自动的分配一个线程给新连接的客户?这个线程时
怎样实现的?当数据处理完毕之后,服务器又怎样自动的去关闭这个线程?由于我的客户
端比较多,假设又100个,当出现好多个客户同时连接到服务器时,服务器如何给这些连
接一一分配线程?会不会出现由于线程分配不过来而丢失数据的现象?如果会出现这种现
象,该如何解决?会不会象打印队列那样编一个队列?
用C++builder写时用到了这个函数是什么意思?
TwinSocketStream * pStream= new TwinSocketStream(ClientSocket,60000);
(不知那位大虾那里有“阻塞线程”的程序,请参考一下,谢谢!)
到数据后先分析数据然后再将数据写到数据库中。在整个过程进行的同时还要把数据库中的
数据显示出来,每隔1分钟刷新一次数据库。
我的总体思路是用多线程完成,其中显示数据部分用一个线程,其他部分(客户和服务器的
连接,服务器接收客户提交的数据,把数据写到数据库中去)用多个线程。现在有如下的问
题:
1.我作过这样的实验,用API函数来设计线程。我的程序如下:
(数据表名称:text,字段有两个:Ip和ReceText,分别用来储存接收信息的来源IP和起内容)。
function ThreadProc(Var receive:string,Var IpStr:string):LongInt;Stdcall;
begin
query1.close;
query1.sql.clear;
query1.sql.add('insert into text (Ip,ReceText)');
query1.sql.add('values("'+receive+'","'+IpStr+'")');
query1.execusql;
end;
在ServerSocket1的OnClientRead()事件中添加调用这个函数的程序:
Rece:=Socket.ReceiveText;
IpStr:=Socket.RemoteAddress;
try
Hthread1:=CreateThread(nil,0,@ThreadProc(Rece,IpStr),0,nil,ThreadID);
Finally
If (Hthread1=0) then
ShowMessage('创建线程失败!');
end;
我写这个线程的用意很简单,就是当服务器来一个客户的提交时产生一个线程,然后再在这
个线程中完成写数据库的操作。但是,在运行时产生了"Variable
required "样的错误。我现在的疑问是:
1.当用API函数产生线程时,如何传递参数?(在显示数据时由于不需要传递参数,就可以用API函数)。
2.我的这个思路对不对?如果不对,清问为什么?
(服务器的服务类型时"非阻塞")。
2.于上述方法不行,我就改用下面的方法。这是在《Delphi 4.0核心编程》中的一个例子,
我改编了一下,显示用API函数写的线程,而写操作用了一个其中的类。代码如下:
//定义的类:
TQueryThread=class (TThread)
private
FSession:TSession;
FQuery:TQuery;
FDataSource:TDataSource;
FQueryException:Exception;
procedure connectDatasource;
procedure ShowqueryError;
protected
procedure execute;override;
public
constructor create(Session:Tsession;
query:Tquery;
datasource:Tdatasource);virtual;
end;
//类的实现:
constructor TqueryThread.create(Session:Tsession;query:Tquery;datasource:Tdatasource);
begin
inherited create(true);
Fquery:=query;
Fdatasource:=datasource;
FreeOnterminate:=true;
resume;
end;
procedure TqueryThread.execute;
begin
try
FQuery.Open;
synchronize(connectdatasource);
except
Fqueryexception:=Exceptobject as exception;
synchronize(showqueryError);
showmessage('发生错误1!');
end;
end;
procedure TqueryThread.connectDatasource;
begin
FdataSource.DataSet:=fquery;
end;
procedure TqueryThread.ShowqueryError;
begin
application.ShowException(Fqueryexception);
ShowMessage('发生错误2!');
end;
procedure Runbackgroundquery(session:Tsession;query:Tquery;datasource:Tdatasource);
begin
Tquerythread.create(Session,query,datasource);
end;
{$R *.DFM}
procedure TForm1.Timer1Timer(Sender: TObject);
var //每隔1秒钟重新访问一次数据库.
i,j:integer;
begin
query1.close;
query1.sql.Clear;
query1.sql.add('select * from test');
query1.open;
runbackgroundquery(session1,query1,datasource1);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
//创建时打开ServerSocket
serversocket1.open;
end;
procedure TForm1.ServerSocket1Accept(Sender: TObject;
Socket: TCustomWinSocket);//如果客户端连接成功,则调用此过程.
begin
showmessage('连接成功!');
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);//当有一个客户端提交数据时,调用这个过程.
Var //然后产生一个线程,将数据写入数据库.
Rece,IpStr:string;
begin
Rece:=socket.ReceiveText;
IpStr:=socket.remoteaddress;
query1.close;
query1.sql.Clear;
query1.sql.add('insert into test (Ip,text)');
query1.sql.add('values("'+IpStr+'","'+Rece+'")');
query1.ExecSQL;
Runbackgroundquery(session1,query1,datasource1);
end;
此刻运行正常,向数据库中写数据也正常。但是,每接收一次数据就产生一次"Error creating curor handle "的错误。这是为什么?
后来我把客户端的程序改了一下,在OnWrite()事件中把socket.sendtext()该为:
while not falsedo
begin
sleep(10);
socket.sendtext();
end;
即每过0.01秒把数据循环发一次.但在服务器端接收时却把这些按不同的包发过来的数据
当成一个包处理了:把所有数据写到一条记录中去了!于是我就想到是不是由于相临两次发
送的包之间的间隔太短,才使得服务器认为这是一个数据包?(事实证明的确是这样.后来我
把时间间隔改了一下,改成1秒后,服务器又可认出不同的包了).那么会不会产生这样的情
况:两个来自不同客户端的数据包在同时到达服务器时被服务器认为是同一个包或者是只
能处理一个而将其中一个包丢弃掉?
3. 后来我又看到有的资料上介绍类似于我这个问题的解决办法是用"阻塞线程"解决.但是,
如何用"阻塞线程"解决这个问题?当一个客户端连接到服务器时,服务器如何判断的出此
时已经有一个客户连接?服务器又如何自动的分配一个线程给新连接的客户?这个线程时
怎样实现的?当数据处理完毕之后,服务器又怎样自动的去关闭这个线程?由于我的客户
端比较多,假设又100个,当出现好多个客户同时连接到服务器时,服务器如何给这些连
接一一分配线程?会不会出现由于线程分配不过来而丢失数据的现象?如果会出现这种现
象,该如何解决?会不会象打印队列那样编一个队列?
用C++builder写时用到了这个函数是什么意思?
TwinSocketStream * pStream= new TwinSocketStream(ClientSocket,60000);
(不知那位大虾那里有“阻塞线程”的程序,请参考一下,谢谢!)