zoukankan      html  css  js  c++  java
  • 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;
    总结:通过客户端和服务器端的多线程控制,当我们需要对大信息量的数据处理的时候,尤为方便,而且能够很大程度上提高网络资源的利用率。
  • 相关阅读:
    转载:SQL server2005 里面没有management studio!下载SQL开发版本
    LInux、Ubuntu、win7、win8纯净版 镜像包链接地址 收集
    [转]Lucene经验总结 (转注:较旧,但有干货)
    几篇调试IIS内存过高或CPU过高的好文章
    Web应用程序
    使用ASP.NET State Server实现多应用程序间共享Session State
    [转]使用visual studio进行web应用程序性能测试
    [转] ASP.NET WEB API程序在VS启动或发布到IIS后启动后发生
    [转]优化Redis内存的9个要点
    [转]使用Memcached的8个要点
  • 原文地址:https://www.cnblogs.com/hnxxcxg/p/2940827.html
Copyright © 2011-2022 走看看