WinSock编程的多线程控制
版权全部 codesky.net 2003-2005
发表时间:2004-11-16关键字:Sockets,多线程
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; |
总结:经过客户端和服务器端的多线程控制,当咱们须要对大信息量的数据处理的时候,尤其方便,并且可以很大程度上提升网络资源的利用率。目前咱们正在研究经过线程控制来对数据库的查询进行优化处理以及数据发送问题!