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;
设置为阻塞模式。