📄 udiiocpsocketserver.pas
字号:
Result := False;
Exit;
end;
//WaitThread事件列表m_hPostAcceptEvent
m_hWaitEventList[1] := m_hPostAcceptEvent;
//WSAEventSelectI/O模型处理Accept事件
m_hListenThreadEvent := WSACreateEvent;
if (m_hListenThreadEvent = WSA_INVALID_EVENT) then begin
AppendDisplayMsg(Format('WSACreateEvent() 创建失败: %d.', [WSAGetLastError()]));
WSACloseEvent(m_hListenThreadEvent);
Winsock2.closesocket(m_sListenSocket);
Result := FALSE;
Exit
end;
//WaitThread事件列表m_hListenThreadEvent
m_hWaitEventList[2] := m_hListenThreadEvent;
//注册FD_ACCEPT事件。
//如果投递的AcceptEx I/O不够,线程会接收到FD_ACCEPT网络事件,说明应该投递更多的AcceptEx I/O
nRet := WSAEventSelect(m_sListenSocket, m_hListenThreadEvent, FD_ACCEPT);
if (nRet = SOCKET_ERROR) then begin
AppendErrorMessage(Format('WSAAsyncSelect()调用失败: %d.', [WSAGetLastError()]));
WSACloseEvent(m_hListenThreadEvent);
Winsock2.closesocket(m_sListenSocket);
Result := FALSE;
Exit;
end;
//加载扩展函数AcceptEx
if ( WSAIoctl( m_sListenSocket,
SIO_GET_EXTENSION_FUNCTION_POINTER,
@GuidAcceptEx,
sizeof(GuidAcceptEx),
@@m_lpfnAcceptEx,
sizeof(@m_lpfnAcceptEx),
@dwBytesReceived,
nil,
nil) = SOCKET_ERROR ) then begin
AppendErrorMessage(Format('WSAIoctl 加载AcceptEx函数失败: %d.', [WSAGetLastError()]));
WSACloseEvent(m_hListenThreadEvent);
Winsock2.closesocket(m_sListenSocket);
Result := FALSE;
Exit;
end;
//加载扩展函数GetAcceptExSockaddrs
if ( WSAIoctl( m_sListenSocket,
SIO_GET_EXTENSION_FUNCTION_POINTER,
@GuidGetAcceptExSockaddrs,
sizeof(GuidGetAcceptExSockaddrs),
@@m_lpfnGetAcceptExSockaddrs,
sizeof(@m_lpfnGetAcceptExSockaddrs),
@dwBytesReceived,
nil,
nil) = SOCKET_ERROR ) then begin
AppendErrorMessage(Format('WSAIoctl 加载GetAcceptExSockaddrs函数失败: %d.', [WSAGetLastError()]));
WSACloseEvent(m_hListenThreadEvent);
Winsock2.closesocket(m_sListenSocket);
Result := FALSE;
Exit;
end;
FillChar(sock_Addr, SizeOf(sock_Addr), 0);
sock_Addr.sin_family := AF_INET;
sock_Addr.sin_addr.S_addr := INADDR_ANY;
sock_Addr.sin_port := htons(m_nListenPort);
//绑定套接字
nRet := Bind(m_sListenSocket, @sock_Addr, sizeof(sock_Addr));
if (nRet = SOCKET_ERROR) then begin
AppendErrorMessage(Format('bind() 调用失败: %d.', [WSAGetLastError()]));
WSACloseEvent(m_hListenThreadEvent);
Winsock2.closesocket(m_sListenSocket);
Result := FALSE;
Exit;
end;
//侦听
nRet := Listen(m_sListenSocket, 5);
if (nRet = SOCKET_ERROR) then begin
AppendErrorMessage(Format('listen() 调用失败: %d.', [WSAGetLastError()]));
WSACloseEvent(m_hListenThreadEvent);
Winsock2.closesocket(m_sListenSocket);
Result := FALSE;
Exit;
end;
//将监听套节字关联到完成端口,注意,这里为它传递的CompletionKey为0
AssociateSocketWithCompletionPort(m_sListenSocket, m_hCompletionPort, DWORD(0));
//设置状态,允许客户端连接
m_bAcceptConnections := TRUE;
//创建侦听线程,并挂起
FDIListenThread := TDIListenThread.Create(self);
if (FDIListenThread = nil) then begin
AppendErrorMessage(Format('创建ListnerThreadProc线程错误: %d.', [WSAGetLastError()]));
WSACloseEvent(m_hListenThreadEvent);
Winsock2.closesocket(m_sListenSocket);
Result := FALSE;
Exit;
end;
FDIListenThread.Run;
Result := TRUE;
end;
function TDIIocpSocketServer.PostWSACloseSocket(pClientChannel: TDIClientChannel; pDIBuffer: TDIBuffer): Boolean;
begin
if pClientChannel = nil then begin
AppendErrorMessage('PostWSACloseSocket投递CloseSocket I/O操作失败, pClientChannel is NULL.');
Result := False;
Exit;
end;
if pDIBuffer = nil then begin
AppendErrorMessage('PostWSACloseSocket投递CloseSocket I/O操作失败, pDIBuffer is NULL.');
Result := False;
Exit;
end;
try
pClientChannel.FContextLock.Lock;
pDIBuffer.SetOperation(IOWSACloseSocket);
pDIBuffer.SetupRead;
if (PostQueuedCompletionStatus( m_hCompletionPort,
0,
DWORD(Pointer(pClientChannel)),
@pDIBuffer.PerHandleData.m_overlap) = False) then
begin
AppendErrorMessage(Format('PostWSACloseSocket失败: %d.',[WSAGetLastError()]));
pClientChannel.FContextLock.UnLock;
Result := FALSE;
Exit;
end;
finally
pClientChannel.FContextLock.UnLock;
end;
Result := TRUE;
end;
procedure TDIIocpSocketServer.ProcessIOMessage(pClientChannel: TDIClientChannel; pDIBuffer: TDIBuffer; dwIoSize: DWORD);
begin
case pDIBuffer.GetOperation of
IOWSAAcceptEx:
begin
OnWSAAcceptEx(pDIBuffer);
end;
IOWSARecv:
begin
//OnWSARecv(pClientChannel, pDIBuffer, dwIoSize);
end;
IOWSASend:
begin
//OnWSASend(pClientChannel, pDIBuffer, dwIoSize);
end;
end;
end;
procedure TDIIocpSocketServer.IOWorkerThreadProc;
var
bIORet: Boolean;
dwIOSize: DWORD;
dwIOError: DWORD;
pBuffer: TDIBuffer;
pClientChannel: TDIClientChannel;
pHandleData: PPerHandleData;
begin
//m_hShutdownEvent事件,线程退出。
while (WaitForSingleObject(m_hShutdownEvent, INFINITE) <> WAIT_OBJECT_0) do begin
pHandleData := nil;
pClientChannel := nil;
pBuffer := nil;
dwIOSize := 0;
bIORet := GetQueuedCompletionStatus( m_hCompletionPort,
dwIOSize,
DWORD(pClientChannel),
POVERLAPPED(pHandleData),
INFINITE );
//PostQueuedCompletionStatus检查状态-1,以便退出线程
if (dwIOSize = $FFFFFFFF) then Exit;
if (pHandleData<> nil) then pBuffer := TDIBuffer(pHandleData.pDIBuffer);
//计数减一
if (pClientChannel<>nil) then pClientChannel.ExitIOLoop(pBuffer);
if (bIORet) then
begin
//一.得到正常断开的通知
//GetQueuedCompletionStatus返回true,并且dwIOSize返回0 且 FClientChannel, pHandleData不为空
if ( (dwIOSize=0) and (pBuffer<>Nil) and (pClientChannel<>nil) ) then begin
//触发关闭Socket套接字事件
//pIOCPServer->OnCloseSocketEvent(lpClientContext, pOverlapBuff);
//pIOCPServer->DisconnectClient(lpClientContext);
//pIOCPServer->ReleaseClientContextToPool(lpClientContext);
//if (pBuffer<> nil) then pIOCPServer.m_FreeDIBufferList.ReleaseBufferToPool(pBuffer);
continue;
end;
//二.收到用户自定义退出消息
if (pBuffer<>Nil) and
(pBuffer.GetOperation = IOWSACloseSocket) and
(pClientChannel<>nil) then begin
//触发关闭Socket套接字事件
//pIOCPServer->OnCloseSocketEvent(lpClientContext, pOverlapBuff);
//pIOCPServer->DisconnectClient(lpClientContext);
//pIOCPServer->ReleaseClientContextToPool(lpClientContext);
//if (pBuffer<> nil) then pIOCPServer.m_FreeDIBufferList.ReleaseBufferToPool(pBuffer);
continue;
end;
//消息分发
//if (FBuffer<>Nil) pIOCPServer.ProcessIOMessage(FClientChannel, FBuffer, dwIOSize);
end
else
begin
//三.异常断开(未得到正常断开的通知)
//GetQueuedCompletionStatus 返回false
//GetLastError返回ERROR_NETNAME_DELETED或者ERROR_INVALID_PARAMETER
if (not bIORet) then begin
dwIOError := GetLastError();
if ( dwIOError<>WAIT_TIMEOUT ) then begin
if (pClientChannel<>nil) then begin
//释放上下文
if (dwIOError = ERROR_NETNAME_DELETED) or (dwIOError = ERROR_INVALID_PARAMETER) then
begin
//触发关闭Socket套接字事件
//pIOCPServer->OnCloseSocketEvent(lpClientContext, pOverlapBuff);
//pIOCPServer->DisconnectClient(lpClientContext);
//pIOCPServer->ReleaseClientContextToPool(lpClientContext);
//if (pBuffer<> nil) then pIOCPServer.m_FreeDIBufferList.ReleaseBufferToPool(pBuffer);
end;
continue;
end;
if (pBuffer<> nil) then m_FreeDIBufferList.ReleaseBufferToPool(pBuffer);
continue;
end;
end;
end;
end;
end;
function TDIIocpSocketServer.SetupIOWorkers: Boolean;
var
i: Integer;
dwThreadID: DWORD;
hThread: THandle;
WorkerThread: TDIWorkerThread;
begin
SetLength(m_WrokThreads, m_nMaxIOCPIOWorkers);
for i := 1 to m_nMaxIOCPIOWorkers do begin
WorkerThread := TDIWorkerThread.Create(self);
m_WrokThreads[i].nThread := i+1;
m_WrokThreads[i].FSocketServer := self;
m_WrokThreads[i].FDIThread := WorkerThread;
m_WrokThreads[i].hEvent := WorkerThread.Handle;
WorkerThread.Run;
end;
Result := TRUE;
end;
function TDIIocpSocketServer.Startup: Boolean;
var
bRet: LongBool;
begin
if (m_bServerStarted) then begin
Result := False;
Exit;
end;
AppendDisplayMsg(Format('IOCP服务器端启动, 系统版本号: %s.', [IOCP_SERVER_VERSION]));
//停止服务内核对象
m_hShutdownEvent := CreateEvent(nil, TRUE, FALSE, nil);
if (m_hShutdownEvent = WSA_INVALID_EVENT) then begin
AppendDisplayMsg(Format('WSACreateEvent() 创建失败: %d.', [WSAGetLastError()]));
WSACloseEvent(m_hShutdownEvent);
Result := False;
Exit;
end;
AppendDisplayMsg(Format('服务器允许客户端最大的连接数: %d.', [FMaxNumConnections]));
bRet := CreateCompletionPort;
if (bRet) then
AppendDisplayMsg('创建完成端口成功.')
else
begin
AppendDisplayMsg('创建完成端口失败.');
Result := FALSE;
Exit;
end;
//侦听端口
if ( m_nListenPort>0 ) then begin
//服务器端启动侦听线程
bRet := SetupListner();
if(bRet) then
AppendDisplayMsg('服务器端启动侦听线程.')
else
begin
AppendErrorMessage('系统异常错误,服务器端侦听线程启动失败.');
Result := FALSE;
Exit;
end;
end;
bRet := SetupIOWorkers();
if(bRet) then
AppendDisplayMsg('服务器端工作线程启动.')
else
begin
AppendErrorMessage('系统异常错误,服务器端工作线程启动失败.');
Result := FALSE;
Exit;
end;
if (bRet) then begin
m_bServerStarted := TRUE;
AppendDisplayMsg(Format('IOCP服务器端侦听地址: %s, 端口号:%d.', [GetHostIPAddr(), m_nListenPort]));
AppendDisplayMsg('IOCP服务器端启动成功.');
end;
Result := TRUE;
end;
procedure TDIIocpSocketServer.ShutDown;
begin
end;
{
procedure TDITcpSocketServer.DisconnectClient(FClientChannel: TDIClientChannel);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -