TserverSocket 分析1

来源:互联网 发布:php一维数组转字符串 编辑:程序博客网 时间:2024/04/29 13:17

TserverSocket 分析

Servertype 有两个值stNonBlocking stThreadBlocking

1、  先讨论stThreadBlocking

这种类型的server 从字面意思上看有thread,他一定使用了线程了

TServerWinSocket.Listen

  if FConnected and (ServerType = stThreadBlocking) then

FServerAcceptThread := TServerAcceptThread.Create(False, Self);

Server监听之后就会创建一个接受线程。

 

看看这个线程做了什么

  while not Terminated do

FServerSocket.Accept(FServerSocket.SocketHandle);

很简单的代码,就是不停的accept客户的连接

 

转到TServerWinSocket.Accept

    ClientWinSocket := WinSock.accept(Socket, @Addr, @Len);

    if ClientWinSocket <> INVALID_SOCKET then

    begin

      ClientSocket := GetClientSocket(ClientWinSocket);

      if Assigned(FOnSocketEvent) then

        FOnSocketEvent(Self, ClientSocket, seAccept);

      if FServerType = stThreadBlocking then

      begin

        ClientSocket.ASyncStyles := [];

        GetServerThread(ClientSocket);

      end;

end;

接受客户的连接,然后转换socket TserverClientWinSocket类(GetClientSocket的功能),设置style[],调用 GetServerThread(ClientSocket);

 

我们继续TServerWinSocket.GetServerThread

    for I := 0 to FActiveThreads.Count - 1 do

      if TServerClientThread(FActiveThreads[I]).ClientSocket = nil then

      begin

        Result := FActiveThreads[I];

        Result.ReActivate(ClientSocket);

        Break;

      end;

看线程池中有没有空闲的线程。

  if Result = nil then

  begin

    if Assigned(FOnGetThread) then FOnGetThread(Self, ClientSocket, Result);

    if Result = nil then Result := DoCreateThread(ClientSocket);

  end;

没有的就DoCreateThread

TServerWinSocket.DoCreateThread

  Result := TServerClientThread.Create(False, ClientSocket);

产生一个新的线程TserverClientThread

 

这个新的客户端线程在做什么呢TServerClientThread.ClientExecute

  while not Terminated and ClientSocket.Connected do

  begin

    FD_ZERO(FDSet);

    FD_SET(ClientSocket.SocketHandle, FDSet);

    TimeVal.tv_sec := 0;

    TimeVal.tv_usec := 500;

    if (select(0, @FDSet, nil, nil, @TimeVal) > 0) and not Terminated then

      if ClientSocket.ReceiveBuf(FDSet, -1) = 0 then Break

      else Synchronize(DoRead);

    if (select(0, nil, @FDSet, nil, @TimeVal) > 0) and not Terminated then

      Synchronize(DoWrite);

  end;

原来不停的调用select来读写。

 

总结一下

listen的时候生成一个接受线程TserverAcceptThread,线程每接受到一个客户端,生成一个线程TserverClientThread,不停select

那为什么脚threadblock呢,原来在接受到客户端后设置ClientSocket.ASyncStyles := [];

TCustomWinSocket.DoSetAsyncStyles

  if FASyncStyles = [] then

  begin

    Blocking := 0;

    ioctlsocket(FSocket, FIONBIO, Blocking);

  end;

设置为阻塞模式。