📄 jsocket.pas
字号:
FActiveThreads := TList.Create;
FListLock := TCriticalSection.Create;
inherited Create(ASocket);
FAsyncStyles := [asAccept];
end;
destructor TServerWinSocket.Destroy;
begin
inherited Destroy;
FConnections.Free;
FActiveThreads.Free;
FListLock.Free;
end;
procedure TServerWinSocket.AddClient(AClient: TServerClientWinSocket);
begin
FListLock.Enter;
try
if FConnections.IndexOf(AClient) < 0 then
FConnections.Add(AClient);
finally
FListLock.Leave;
end;
end;
procedure TServerWinSocket.RemoveClient(AClient: TServerClientWinSocket);
begin
FListLock.Enter;
try
FConnections.Remove(AClient);
finally
FListLock.Leave;
end;
end;
procedure TServerWinSocket.AddThread(AThread: TServerClientThread);
begin
FListLock.Enter;
try
if FActiveThreads.IndexOf(AThread) < 0 then
begin
FActiveThreads.Add(AThread);
if FActiveThreads.Count <= FThreadCacheSize then
AThread.KeepInCache := True;
end;
finally
FListLock.Leave;
end;
end;
procedure TServerWinSocket.RemoveThread(AThread: TServerClientThread);
begin
FListLock.Enter;
try
FActiveThreads.Remove(AThread);
finally
FListLock.Leave;
end;
end;
procedure TServerWinSocket.ClientEvent(Sender: TObject; Socket: TCustomWinSocket;
SocketEvent: TSocketEvent);
begin
case SocketEvent of
seAccept,
seLookup,
seConnecting,
seListen:
begin end;
seConnect: ClientConnect(Socket);
seDisconnect: ClientDisconnect(Socket);
seRead: ClientRead(Socket);
seWrite: ClientWrite(Socket);
end;
end;
procedure TServerWinSocket.ClientError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
ClientErrorEvent(Socket, ErrorEvent, ErrorCode);
end;
function TServerWinSocket.GetActiveConnections: Integer;
begin
Result := FConnections.Count;
end;
function TServerWinSocket.GetConnections(Index: Integer): TCustomWinSocket;
begin
Result := FConnections[Index];
end;
function TServerWinSocket.GetActiveThreads: Integer;
var
I: Integer;
begin
FListLock.Enter;
try
Result := 0;
for I := 0 to FActiveThreads.Count - 1 do
if TServerClientThread(FActiveThreads[I]).ClientSocket <> nil then
Inc(Result);
finally
FListLock.Leave;
end;
end;
function TServerWinSocket.GetIdleThreads: Integer;
var
I: Integer;
begin
FListLock.Enter;
try
Result := 0;
for I := 0 to FActiveThreads.Count - 1 do
if TServerClientThread(FActiveThreads[I]).ClientSocket = nil then
Inc(Result);
finally
FListLock.Leave;
end;
end;
procedure TServerWinSocket.Accept(Socket: TSocket);
var
ClientSocket: TServerClientWinSocket;
ClientWinSocket: TSocket;
Addr: TSockAddrIn;
Len: Integer;
OldOpenType, NewOpenType: Integer;
begin
Len := SizeOf(OldOpenType);
if getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@OldOpenType),
Len) = 0 then
try
if FServerType = stThreadBlocking then
begin
NewOpenType := SO_SYNCHRONOUS_NONALERT;
setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@NewOpenType), Len);
end;
Len := SizeOf(Addr);
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;
finally
Len := SizeOf(OldOpenType);
setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@OldOpenType), Len);
end;
end;
procedure TServerWinSocket.Disconnect(Socket: TSocket);
var
SaveCacheSize: Integer;
begin
Lock;
try
SaveCacheSize := ThreadCacheSize;
try
ThreadCacheSize := 0;
while FActiveThreads.Count > 0 do
with TServerClientThread(FActiveThreads.Last) do
begin
FreeOnTerminate := False;
Terminate;
FEvent.SetEvent;
if (ClientSocket <> nil) and ClientSocket.Connected then
ClientSocket.Close;
WaitFor;
Free;
end;
while FConnections.Count > 0 do
TCustomWinSocket(FConnections.Last).Free;
if FServerAcceptThread <> nil then
FServerAcceptThread.Terminate;
inherited Disconnect(Socket);
FServerAcceptThread.Free;
FServerAcceptThread := nil;
finally
ThreadCacheSize := SaveCacheSize;
end;
finally
Unlock;
end;
end;
function TServerWinSocket.DoCreateThread(ClientSocket: TServerClientWinSocket): TServerClientThread;
begin
Result := TServerClientThread.Create(False, ClientSocket);
end;
procedure TServerWinSocket.Listen(var Name, Address, Service: string; Port: Word;
QueueSize: Integer);
begin
inherited Listen(Name, Address, Service, Port, QueueSize, ServerType = stThreadBlocking);
if FConnected and (ServerType = stThreadBlocking) then
FServerAcceptThread := TServerAcceptThread.Create(False, Self);
end;
procedure TServerWinSocket.SetServerType(Value: TServerType);
begin
if Value <> FServerType then
if not FConnected then
begin
FServerType := Value;
if FServerType = stThreadBlocking then
ASyncStyles := []
else ASyncStyles := [asAccept];
end else raise ESocketError.CreateRes(@sCantChangeWhileActive);
end;
procedure TServerWinSocket.SetThreadCacheSize(Value: Integer);
var
Start, I: Integer;
begin
if Value <> FThreadCacheSize then
begin
if Value < FThreadCacheSize then
Start := Value
else Start := FThreadCacheSize;
FThreadCacheSize := Value;
FListLock.Enter;
try
for I := 0 to FActiveThreads.Count - 1 do
with TServerClientThread(FActiveThreads[I]) do
KeepInCache := I < Start;
finally
FListLock.Leave;
end;
end;
end;
function TServerWinSocket.GetClientSocket(Socket: TSocket): TServerClientWinSocket;
begin
Result := nil;
if Assigned(FOnGetSocket) then FOnGetSocket(Self, Socket, Result);
if Result = nil then
Result := TServerClientWinSocket.Create(Socket, Self);
end;
procedure TServerWinSocket.ThreadEnd(AThread: TServerClientThread);
begin
if Assigned(FOnThreadEnd) then FOnThreadEnd(Self, AThread);
end;
procedure TServerWinSocket.ThreadStart(AThread: TServerClientThread);
begin
if Assigned(FOnThreadStart) then FOnThreadStart(Self, AThread);
end;
function TServerWinSocket.GetServerThread(ClientSocket: TServerClientWinSocket): TServerClientThread;
var
I: Integer;
begin
Result := nil;
FListLock.Enter;
try
for I := 0 to FActiveThreads.Count - 1 do
if TServerClientThread(FActiveThreads[I]).ClientSocket = nil then
begin
Result := FActiveThreads[I];
Result.ReActivate(ClientSocket);
Break;
end;
finally
FListLock.Leave;
end;
if Result = nil then
begin
if Assigned(FOnGetThread) then FOnGetThread(Self, ClientSocket, Result);
if Result = nil then Result := DoCreateThread(ClientSocket);
end;
end;
function TServerWinSocket.GetClientThread(ClientSocket: TServerClientWinSocket): TServerClientThread;
var
I: Integer;
begin
Result := nil;
FListLock.Enter;
try
for I := 0 to FActiveThreads.Count - 1 do
if TServerClientThread(FActiveThreads[I]).ClientSocket = ClientSocket then
begin
Result := FActiveThreads[I];
Break;
end;
finally
FListLock.Leave;
end;
end;
procedure TServerWinSocket.ClientConnect(Socket: TCustomWinSocket);
begin
if Assigned(FOnClientConnect) then FOnClientConnect(Self, Socket);
end;
procedure TServerWinSocket.ClientDisconnect(Socket: TCustomWinSocket);
begin
if Assigned(FOnClientDisconnect) then FOnClientDisconnect(Self, Socket);
if ServerType = stNonBlocking then Socket.DeferFree;
end;
procedure TServerWinSocket.ClientRead(Socket: TCustomWinSocket);
begin
if Assigned(FOnClientRead) then FOnClientRead(Self, Socket);
end;
procedure TServerWinSocket.ClientWrite(Socket: TCustomWinSocket);
begin
if Assigned(FOnClientWrite) then FOnClientWrite(Self, Socket);
end;
procedure TServerWinSocket.ClientErrorEvent(Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
if Assigned(FOnClientError) then FOnClientError(Self, Socket, ErrorEvent, ErrorCode);
end;
{ TServerAcceptThread }
constructor TServerAcceptThread.Create(CreateSuspended: Boolean;
ASocket: TServerWinSocket);
begin
FServerSocket := ASocket;
inherited Create(CreateSuspended);
end;
procedure TServerAcceptThread.Execute;
begin
while not Terminated do
FServerSocket.Accept(FServerSocket.SocketHandle);
end;
{ TServerClientThread }
constructor TServerClientThread.Create(CreateSuspended: Boolean;
ASocket: TServerClientWinSocket);
begin
FreeOnTerminate := True;
FEvent := TSimpleEvent.Create;
inherited Create(True);
Priority := tpHigher;
ReActivate(ASocket);
if not CreateSuspended then Resume;
end;
destructor TServerClientThread.Destroy;
begin
FClientSocket.Free;
FEvent.Free;
inherited Destroy;
end;
procedure TServerClientThread.ReActivate(ASocket: TServerClientWinSocket);
begin
FClientSocket := ASocket;
if Assigned(FClientSocket) then
begin
FServerSocket := FClientSocket.ServerWinSocket;
FServerSocket.AddThread(Self);
FClientSocket.OnSocketEvent := HandleEvent;
FClientSocket.OnErrorEvent := HandleError;
FEvent.SetEvent;
end;
end;
procedure TServerClientThread.DoHandleException;
begin
if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
if FException is Exception then
begin
if Assigned(ApplicationShowException) then
ApplicationShowException(FException);
end else
SysUtils.ShowException(FException, nil);
end;
procedure TServerClientThread.DoRead;
begin
ClientSocket.ServerWinSocket.Event(ClientSocket, seRead);
end;
procedure TServerClientThread.DoTerminate;
begin
inherited DoTerminate;
if Assigned(FServerSocket) then
FServerSocket.RemoveThread(Self);
end;
procedure TServerClientThread.DoWrite;
begin
FServerSocket.Event(ClientSocket, seWrite);
end;
procedure TServerClientThread.HandleEvent(Sender: TObject; Socket: TCustomWinSocket;
SocketEvent: TSocketEvent);
begin
Event(SocketEvent);
end;
procedure TServerClientThread.HandleError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
Error(ErrorEvent, ErrorCode);
end;
procedure TServerClientThread.Event(SocketEvent: TSocketEvent);
begin
FServerSocket.ClientEvent(Self, ClientSocket, SocketEvent);
end;
procedure TServerClientThread.Error(ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
FServerSocket.ClientError(Self, ClientSocket, ErrorEvent, ErrorCode);
end;
procedure TServerClientThread.HandleException;
begin
FException := Exception(ExceptObject);
try
if not (FException is EAbort) then
Synchronize(DoHandleException);
finally
FException := nil;
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -