procedure TIocpTcpSocket.RequestAcceptComplete(PerIoData: PIocpPerIoData); var Connection: TIocpSocketConnection; LocalAddrLen, RemoteAddrLen: Integer; PLocalAddr, PRemoteAddr: PSockAddr; begin try // 将连接放到工作连接列表中 try FConnectionListLocker.Enter; Connection := FIdleConnectionList[PerIoData.ClientSocket]; // 如果之前该连接存在于空闲连接列表中则将它移到工作连接列表中 if (Connection <> nil) then begin FConnectionList[PerIoData.ClientSocket] := Connection; FIdleConnectionList.Delete(Connection.FSocket); end else //** 理论上永远不会执行到这里来 begin Connection := FConnectionList[PerIoData.ClientSocket]; if (Connection = nil) then begin Connection := AllocConnection(PerIoData.ClientSocket); FConnectionList[PerIoData.ClientSocket] := Connection; end; end;
// 将Socket邦定到IOCP if not AssociateSocketWithCompletionPort(PerIoData.ClientSocket, Connection) then begin AppendLog('RequestAcceptComplete.AssociateSocketWithCompletionPort failed'); Connection.Release; Exit; end; finally FConnectionListLocker.Leave; end;
Connection.UpdateTick;
// 对于SO_UPDATE_ACCEPT_CONTEXT,最后一个参数optlen实际需要设定为SizeOf(PAnsiChar) // 这一点在MSDN的例子中都是错的!因为经过实际测试发现在64位程序中这里传递SizeOf(PerIoData.ListenSocket) // 的话会报错:10014,系统检测到在一个调用中尝试使用指针参数时的无效指针地址。 // 也就是说这里的optlen实际上应该传递的是一个指针的长度(应该跟内存对齐有关系) if (setsockopt(PerIoData.ClientSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, PAnsiChar(@PerIoData.ListenSocket), SizeOf(PAnsiChar)) = SOCKET_ERROR) then begin AppendLog('%s.RequestAcceptComplete.setsockopt.SO_UPDATE_ACCEPT_CONTEXT ERROR %d=%s', [ClassName, WSAGetLastError, SysErrorMessage(WSAGetLastError)], ltWarning); Connection.Disconnect; Exit; end;
// 获取连接地址信息 GetAcceptExSockaddrs(@PerIoData.Buffer.AcceptExBuffer[0], 0, SizeOf(TAddrBuffer), SizeOf(TAddrBuffer), PLocalAddr, LocalAddrLen, PRemoteAddr, RemoteAddrLen);
if not Connection.InitSocket then begin Connection.Disconnect; Exit; end;
// 解析地址信息 ExtractAddrInfo(PRemoteAddr, RemoteAddrLen, Connection.FRemoteIP, Connection.FRemotePort);
// 超过最大允许连接数,断开 if (FMaxClients > 0) and (FConnectionList.Count > FMaxClients) then begin Connection.Disconnect; Exit; end;
if not _TriggerClientConnected(Connection) then Exit;
// 连接建立之后PostZero读取请求 if not Connection.PostReadZero then Exit; except on e: Exception do AppendLog('%s.RequestAcceptComplete ERROR %s=%s', [ClassName, e.ClassName, e.Message], ltException); end; end;
procedure TIocpTcpSocket.RequestConnectComplete(Connection: TIocpSocketConnection); begin try try if not Connection.InitSocket then begin Connection.Disconnect; Exit; end;
try FConnectionListLocker.Enter; FConnectionList[Connection.FSocket] := Connection; finally FConnectionListLocker.Leave; end;
Connection.UpdateTick;
if not _TriggerClientConnected(Connection) then Exit;
// 连接建立之后PostZero读取请求 if not Connection.PostReadZero then Exit; finally Connection.Release; // 对应 AsyncConnect 中的 AddRef; end; except on e: Exception do AppendLog('%s.RequestConnectComplete ERROR %s=%s', [ClassName, e.ClassName, e.Message], ltException); end; end;
procedure TIocpTcpSocket.RequestReadZeroComplete( Connection: TIocpSocketConnection; PerIoData: PIocpPerIoData); begin try try if (Connection.IsClosed) then Exit;
Connection.UpdateTick;
// 正式开始接收数据 Connection.PostRead; finally Connection.Release; // 对应PostReadZero中的AddRef end; except on e: Exception do AppendLog('%s.RequestReadZeroComplete ERROR %s=%s', [ClassName, e.ClassName, e.Message], ltException); end; end;
procedure TIocpTcpSocket.RequestReadComplete(Connection: TIocpSocketConnection; PerIoData: PIocpPerIoData); begin try try Connection.DecPendingRecv;
if (Connection.IsClosed) then Exit;
if (PerIoData.BytesTransfered = 0) or (PerIoData.Buffer.DataBuf.buf = nil) then begin Connection.Disconnect; Exit; end;
Connection.UpdateTick;
// PerIoData.Buffer.DataBuf 就是已接收到的数据,PerIoData.BytesTransfered 是实际接收到的字节数 PerIoData.Buffer.DataBuf.Len := PerIoData.BytesTransfered;
try InterlockedIncrement(FPendingRequest); if not _TriggerClientRecvData(Connection, PerIoData.Buffer.DataBuf.buf, PerIoData.Buffer.DataBuf.len) then Exit; finally InterlockedDecrement(FPendingRequest); end;
// 继续接收客户端数据 Connection.PostReadZero; finally Connection.Release; // 对应PostRead中的AddRef end; except on e: Exception do AppendLog('%s.RequestReadComplete ERROR %s=%s', [ClassName, e.ClassName, e.Message], ltException); end; end; |