WinSock编程的多线程控制

1引言
Windows Sockets规范以U.C. Berkeley大学BSD UNIX中流行的Socket接口为范例定义了一套Microsoft Windows下网络编程接口。它不仅包含了人们所熟悉的Berkeley Socket风格的库函数;也包含了一组针对Windows的扩展库函数,以使程序员能充分地利用Windows消息驱动机制进行编程。
Windows Sockets 规范本意在于提供给应用程序开发者一套简单的API,并让各家网络软件供应商共同遵守。此外,在一个特定版本Windows的基础上,Windows Sockets 也定义了一个二进制接口(ABI),以此来保证应用Windows Sockets API 的应用程序能够在任何网络软件供应商的符合Windows Sockets协议的实现上工作。因此这份规范定义了应用程序开发者能够使用,并且网络软件供应商能够实现的一套库函数调用和相关语义。我们可以使用WinSock在Internet上传输数据和交换信息,而且可以不需要关心网络连接的细节,因而很受网络编程程序员的欢迎。
2 Delphi中Socket的操作方式
Delphi分别使用TClientSocket元件和TServerSocket元件来操纵客户端 Socket和服务器段Socket的连接和通信。根据连接发起的方式以及本地 Socket要连接的目标,Socket之间的连接可以分为:客户端连接、监听连接以及服务器端连接。
(1)所谓客户端连接,是指由客户端的 Socket提出连接请求,要连接的目标是服务器端的Socket。为此,客户端的Socket首先要描述它要连接的服务器端Socket,主要是服务器端Socket的地址和端口号,然后再定位所要连接的服务器端Socket。找到以后,就向服务器端Socket请求连接。此时,服务器端的Socket未必正好处于准备好状态。不过,服务器端Socket会自动维护一个客户请求队列,通过这个队列的优先顺序,会在适当的时候通过请求响应的方式向客户端Socket发出"允许连接"(Accept)的信号,这样便在客户端和服务器端通过Sockets建立了连接!
(2)所谓监听连接,是指服务器端Socket并不定位具体的客户端Socket,而是处于等待连接状态,当服务器端 Socket监听到或者接收到客户端Socket的连接请求的时候,它就响应客户端Socket的请求建立一个新的Socket句柄并与客户端连接,而服务器端Socket继续处于监听状态,这样可以与多个客户端同时建立连接。
(3)所谓服务器端连接,是指当服务器端Socket接收到客户端Socket的连接请求后,就把服务器端Socket的描述发送给客户端。一旦客户端确认了此描述,就建立了连接!
3 线程控制的提出
一旦服务器与客户端建立了连接之后,就可以通过 Internet 传输数据和文件。但是在WinSock中存在两种传输模式"阻塞"和"非阻塞"的概念。
一般都采用非阻塞方式。在客户端,如果把 ClientType特性设置为ctNonBlocking,表示采用非阻塞方式进行连接。当服务器端 Socket试图进行读/写操作的时候,客户端 Socket就会得到通知,即OnRead或者OnWrite事件。
对于服务器端Socket来说,如果把ServerType特性设置为 StNonBlocking,表示采取非阻塞方式进行连接。当客户端 Socket试图进行读/写的时候,服务器端Socket就会得到通知,即OnClientRead或者OnClientWrite事件。
与非阻塞方式不同的是,在阻塞方式下没有诸如OnRead或者OnWrite等异步事件。Socket必须主动去读或者写数据。在读写操作完成之前,其他代码都无法执行,成为了纯粹的独占使用方式,整个应用程序将处于等待状态,大大降低应用程序的性能。
对于客户端Socket来说,如果把 ClientType特性设置为ctBlocking,表示采取阻塞方式进行连接,为了尽可能的减少阻塞方式的负面影响,可以把所有涉及到读写的操作放在一个单独的线程中,这样可以使其他的线程可以继续得到执行。
对于服务器端 Socket来说,如果把ServerType设置为stThreadBlocking,表示采取阻塞方式进行连接。Delphi 中将为每一个阻塞方式的连接自动分配一个新的线程,这样即使一个客户正在进行读写操作,其他的客户也不必等待。
4 在客户端使用多线程技术
在阻塞模式下,为了尽可能的减少阻塞方式的副作用,可以把所有的涉及到读写操作放在一个单独的线程种。为此,需要创建一个新的线程对象,然后重载它的Execute方法,在线程代码中,我们通过TWinSockStream对象来进行读写操作。
Procedure TClientThread.Execute;
Var sStream: TWinSockStream;
sBuffer: string;
Begin
//建一个TWinSocketStream对象实例,设置连接超时
SSteam: = TWinSockStream.Create (ClientSocket.Socket, 60000);
Try //获取和操作命令,直到连接断开或者线程终止
While (not Terminate) and (ClientSocket.Active) do
begin
try
GetNextRequest (sBuffer);
//将请求写回到Server
sStream.Write (sBuffer, Length (sBuffer) + 1);

Except
if not(Except Object is EAbort) then
//处理一些自定义的异常情况
Synchronize(HandleThreadException);
end;
end;
finally
sStream.Free;
end;
End;
5 在服务器端使用多线程技术
在服务器端,Delphi将自动为每一个阻塞方式的连接分配一个新的线程,并通过TServerClientThread来操纵每一个线程。所以不能通过对象库中的向导来创建线程对象,只能手工建立一个TServerClientThread的派生类,然后重载ClientExcute方法。Procedure TServerThread.ClientExcute;
Var sStream:TWinSocketStream;
sBuffer:array[0..9] of char
Begin
//获取和操作命令,直到连接断开或者线程终止
While (not Terminate) and (ClientSocket.Active) do
Begin
Try
sStream:= TWinSocketStream.Create(ClientSocket.Socket,60000);
try //填充SBuffer数组
FillChar(sBuffer,10,0);
//延迟时间60秒
If sStream.WaitForData(60000) then
Begin
If sStream.Read(sBuffer,10)=0 then
ClientSocket.Close;
……
End
Else ClientSocket.Close;
except
HandleException;
end;
Finally
sStream.Free;
end;
end;
End;
总结:通过客户端和服务器端的多线程控制,当我们需要对大信息量的数据处理的时候,尤为方便,而且能够很大程度上提高网络资源的利用率。
posted @ 2008-09-20 09:38  delphi中间件  阅读(369)  评论(0编辑  收藏  举报