📄 udiiocptcpserver.pas
字号:
end;
procedure TDIIocpTcpServer.ListnerThreadProc;
var
i, nRet: Integer;
nIndex, m_nPostAccepts: DWORD;
pBuffer: TDIBuffer;
iRunTime: Integer;
Events: TWSANetworkEvents;
begin
//投递AcceptEx I/O
for i:=1 to m_nInitPostAcceptEx do begin
pBuffer := nil;
pBuffer := m_PoolBuffer.AllocateFreeBufferFromPool;
if (pBuffer = nil) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage('AllocateFreeBufferFromPool错误, ListnerThreadProc线程退出.');
{$ENDIF}
Exit;
end
else
begin
//加入上下文中
m_MapAcceptExBuffer.AddDIBuffer(pBuffer);
if not PostWSAAcceptEx(pBuffer) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage('PostWSAAcceptEx投递Accept I/O错误, ListnerThreadProc线程退出.');
{$ENDIF}
Exit;
end;
end;
end;
iRunTime := 0;
while (TRUE) do
begin
//等网络事件m_hPostAcceptEvent事件和m_hListnerThreadEvent事件
//停止服务内核对象10秒,检查一次, 快速退出
nIndex := WSAWaitForMultipleEvents(3, @m_hWaitEventList[0], FALSE, 10000, FALSE);
if (nIndex = WSA_WAIT_FAILED) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage('WSA_WAIT_FAILED错误, ListnerThreadProc线程退出.');
{$ENDIF}
Break;
end;
//快速退出
if m_bShutDown then Exit;
//超时踢出死连接
if (nIndex = WSA_WAIT_TIMEOUT) then begin
KillDeadClientSocket
end
else
begin
nIndex := nIndex - WAIT_OBJECT_0;
//停止服务内核对象
if (nIndex = 0 ) then begin
{$IFDEF _ICOP_DEBUG}
AppendLogMessage('停止服务内核对象事件, ListnerThreadProc线程退出消息.');
{$ENDIF}
Break;
end
//m_hPostAcceptEvent事件,I/O的线程连接新用户,投递维持一定AcceptEx数量
else if (nIndex = 1 ) then begin
m_nPostAccepts := InterlockedExchange(m_iIOCPPostAccepts, 0);
end
else
begin
if (nIndex = 2 ) then begin
nRet := WSAEnumNetworkEvents( m_sListen,
m_hWaitEventList[nIndex],
@Events );
if (nRet = SOCKET_ERROR) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('异常WSAEnumNetworkEvents错误%d, ListnerThreadProc线程退出.', [WSAGetLastError()]));
{$ENDIF}
Break;
end;
if (Events.lNetworkEvents = FD_ACCEPT) then begin
//多次检查m_bShutDown状态,以便退出线程
if ( (Events.iErrorCode[FD_ACCEPT_BIT] = 0) and
(m_bAcceptConnections) and
(not m_bShutDown) ) then begin
m_nPostAccepts := 50; //增加的个数,这里设为50个
end
else
begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('异常WSAEnumNetworkEvents错误%d, ListnerThreadProc线程退出.', [WSAGetLastError()]));
{$ENDIF}
Break;
end;
end;
end;
end;
//继续投递一定数量的AcceptEx I/O
if m_bAcceptConnections then begin
for i:=1 to m_nPostAccepts do begin
pBuffer := nil;
pBuffer := m_PoolBuffer.AllocateFreeBufferFromPool;
if (pBuffer = nil) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage('AllocateFreeBufferFromPool错误, ListnerThreadProc线程退出.');
{$ENDIF}
Exit;
end
else
begin
//加入上下文中
m_MapAcceptExBuffer.AddDIBuffer(pBuffer);
if not PostWSAAcceptEx(pBuffer) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage('PostWSAAcceptEx投递Accept I/O错误, ListnerThreadProc线程退出.');
{$ENDIF}
Exit;
end;
end;
end;
end;
end;
end;
{$IFDEF _ICOP_DEBUG}
AppendLogMessage('ListnerThreadProc线程退出消息.');
{$ENDIF}
end;
function TDIIocpTcpServer.ListnerStart: Boolean;
var
nRet: Integer;
begin
if not FWinSocket.CreateTCPOverlapSocket(m_sListen) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('创建 Socket监听套按字失败: %d.', [WSAGetLastError()]));
{$ENDIF}
Result := FALSE;
Exit;
end;
if not FWinSocket.SetSocketReUseAddr(m_sListen) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('设置端口复用setsockopt(SO_EXCLUSIVEADDRUSE) 创建失败: %d.', [WSAGetLastError()]));
{$ENDIF}
FWinSocket.CloseWinSocket(m_sListen);
Result := FALSE;
Exit;
end;
//设置Wait线程内核对象列表(AcceptEx线程)
SetLength(m_hWaitEventList, 3);
//停止服务内核对象, 加入WaitThread事件列表
m_hShutdownEvent := CreateEvent(nil, FALSE, FALSE, nil);
if (m_hShutdownEvent = WSA_INVALID_EVENT) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('停止服务内核对象WSACreateEvent() 创建失败: %d.', [WSAGetLastError()]));
{$ENDIF}
FWinSocket.CloseWinSocket(m_sListen);
WSACloseEvent(m_hShutdownEvent);
Result := False;
Exit;
end;
m_hWaitEventList[0] := m_hShutdownEvent;
//投递Accept I/O事件内核对象, 加入WaitThread事件列表
m_hPostAcceptEvent := CreateEvent(nil, FALSE, FALSE, nil);
if (m_hPostAcceptEvent = WSA_INVALID_EVENT) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('投递Accept I/O事件内核对象WSACreateEvent() 创建失败: %d.', [WSAGetLastError()]));
{$ENDIF}
WSACloseEvent(m_hPostAcceptEvent);
FWinSocket.CloseWinSocket(m_sListen);
Result := False;
Exit;
end;
m_hWaitEventList[1] := m_hPostAcceptEvent;
//WSAEventSelectI/O模型处理Accept事件, 加入WaitThread事件列表
m_hListnerThreadEvent := WSACreateEvent;
if (m_hListnerThreadEvent = WSA_INVALID_EVENT) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('WSAEventSelectI/O模型处理Accept事件WSACreateEvent() 创建失败: %d.', [WSAGetLastError()]));
{$ENDIF}
WSACloseEvent(m_hListnerThreadEvent);
WSACloseEvent(m_hPostAcceptEvent);
FWinSocket.CloseWinSocket(m_sListen);
Result := FALSE;
Exit
end;
m_hWaitEventList[2] := m_hListnerThreadEvent;
//注册FD_ACCEPT事件。
//如果投递的AcceptEx I/O不够,线程会接收到FD_ACCEPT网络事件,说明应该投递更多的AcceptEx I/O
nRet := WSAEventSelect(m_sListen, m_hListnerThreadEvent, FD_ACCEPT);
if (nRet = SOCKET_ERROR) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('注册FD_ACCEPT事件 WSAAsyncSelect()调用失败: %d.', [WSAGetLastError()]));
{$ENDIF}
WSACloseEvent(m_hListnerThreadEvent);
WSACloseEvent(m_hPostAcceptEvent);
FWinSocket.CloseWinSocket(m_sListen);
Result := FALSE;
Exit;
end;
//加载扩展函数AcceptEx
if not FWinSocket.LoadAcceptEx(m_sListen, m_lpfnAcceptEx) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('WSAIoctl 加载AcceptEx函数失败: %d.', [WSAGetLastError()]));
{$ENDIF}
WSACloseEvent(m_hListnerThreadEvent);
WSACloseEvent(m_hPostAcceptEvent);
FWinSocket.CloseWinSocket(m_sListen);
Result := FALSE;
Exit;
end;
//加载扩展函数GetAcceptExSockaddrs
if not FWinSocket.LoadAcceptExSockaddrs(m_sListen, m_lpfnGetAcceptExSockaddrs) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('WSAIoctl 加载GetAcceptExSockaddrs函数失败: %d.', [WSAGetLastError()]));
{$ENDIF}
WSACloseEvent(m_hListnerThreadEvent);
WSACloseEvent(m_hPostAcceptEvent);
FWinSocket.CloseWinSocket(m_sListen);
Result := FALSE;
Exit;
end;
//绑定套接字
if not FWinSocket.BindSocket(m_sListen, m_nPort) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('绑定套接字 bind() 调用失败: %d.', [WSAGetLastError()]));
{$ENDIF}
Result := FALSE;
Exit;
end;
//侦听
if not FWinSocket.ListenSocket(m_sListen) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('侦听套接字listen() 调用失败: %d.', [WSAGetLastError()]));
{$ENDIF}
Result := FALSE;
Exit;
end;
//将监听套节字关联到完成端口,注意,这里为它传递的CompletionKey为0
m_IOCompletionPort.AssociateSocketWithCompletionPort(m_sListen, DWORD(0));
//创建侦听线程
m_hListnerThread := TDIListnerThread.Create(self);
if (m_hListnerThread = nil) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('创建ListnerThreadProc线程错误: %d.', [WSAGetLastError()]));
{$ENDIF}
WSACloseEvent(m_hListnerThreadEvent);
WSACloseEvent(m_hPostAcceptEvent);
FWinSocket.CloseWinSocket(m_sListen);
Result := FALSE;
Exit;
end;
m_hListnerThread.Run;
//调置允许连接 计算超时时间
m_bAcceptConnections := TRUE;
m_dLastTime := GetTickCount;
Result := TRUE;
end;
function TDIIocpTcpServer.PostWSAAcceptEx(AcceptExBuffer: TDIBuffer): Boolean;
var
FAcceptSocket: TSocket;
FAcceptReceived: Cardinal;
nRetVal: LongBool;
begin
if not Assigned(AcceptExBuffer) then begin
Result := False;
Exit;
end;
//创建Socket
if not FWinSocket.CreateTCPOverlapSocket(FAcceptSocket) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('PostWSAAcceptEx 创建监听套按字失败: %d.', [WSAGetLastError()]));
{$ENDIF}
Result := FALSE;
Exit;
end;
//设置标志
FAcceptReceived := 0;
AcceptExBuffer.SetOperation(IOWSAAcceptEx);
AcceptExBuffer.SetupRead;
AcceptExBuffer.m_Socket := FAcceptSocket;
nRetVal := m_lpfnAcceptEx( m_sListen,
AcceptExBuffer.m_Socket,
AcceptExBuffer.GetBuffer,
0,
sizeof(TSockAddrIn)+16,
sizeof(TSockAddrIn)+16,
FAcceptReceived,
POverlapped(@AcceptExBuffer.PerHandleData.m_overlap));
if( (nRetVal=FALSE) and (WSAGetLastError()<>WSA_IO_PENDING)) then
begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage(Format('PostAcceptProcess投递Accept I/O操作失败: %d.', [WSAGetLastError()]));
{$ENDIF}
Result := FALSE;
Exit;
end;
//性能分析器 增加AcceptEx I/O数量
{$IFDEF _IOCP_MONITOR}
_DIMonitor.AddIOCPAcceptEx;
{$ENDIF}
Result := TRUE;
end;
function TDIIocpTcpServer.IsSecurityConnection(FDIBuffer: TDIBuffer): Boolean;
var
LocalAddrLen, RemoteAddrLen: Integer;
FLocalAddr, FRemoteAddr: PSockAddr;
sRemoteIPAddr: String;
begin
{
//获取客户端IP地址
m_lpfnGetAcceptExSockaddrs( FDIBuffer.GetBuffer,
0,
sizeof(TSockAddrIn)+16,
sizeof(TSockAddrIn)+16,
FLocalAddr,
LocalAddrLen,
FRemoteAddr,
RemoteAddrLen );
sRemoteIPAddr := FWinSocket.GetRemoteIPAddr(FRemoteAddr^);
}
Result := TRUE;
end;
function TDIIocpTcpServer.OnWSAAcceptEx(FDIBuffer: TDIBuffer; dwIoSize: DWORD): Boolean;
begin
//判断接受到的数据为零,则断开连接。
if(FDIBuffer.m_Socket = INVALID_SOCKET) then begin
{$IFDEF _ICOP_DEBUGERR}
AppendErrorLogMessage('OnWSAAcceptEx m_Socket = INVALID_SOCKET, 关闭客户端Socket连接.');
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -