📄 uditcppacketechosocketserver.pas
字号:
unit uDITcpPacketEchoSocketServer;
interface
uses
Windows, Sysutils, uDIBuffer, uIOCompletionPort, uDIClientContext, uDIProtocol,
uDIIocpTcpServer;
{$I IOCP.inc}
type
PTDIDataPakHead = ^TDIDataPakHead;
TDIDataPakHead = Packed Record
_Head: Byte; //帧头标志 64
_Len: Word; //数据包长度
end;
PTTDIDataPakBody = ^TTDIDataPakBody;
TTDIDataPakBody = Packed record
_Sing: Word; //客户标识
_SocketKey: Word; //Socket标识
_OP: Byte; //控制码 1 回射
end;
//.数据.
PTDIDataPakEnd = ^TDIDataPakEnd;
TDIDataPakEnd = Packed record
_CheckSum: Word; //校验和
_End: Byte; //帧结束符
end;
const
FDataPakHeadLen = SizeOf(TDIDataPakHead);
FDataPakBodyLen = SizeOf(TTDIDataPakBody);
FDataPakEndLen = SizeOf(TDIDataPakEnd);
type
TDITcpPacketEchoSocketServer = class(TDIIocpTcpServer)
private
FDataPakHead: TDIDataPakHead; //包头
FDataPakBody: TTDIDataPakBody;//包体
FDataPakEnd: TDIDataPakEnd; //包尾
private
procedure NewSocketEvent(FClientContext: TDIClientContext);
procedure CloseSocketEvent(FClientContext: TDIClientContext);
procedure RecvCompletedEvent( FClientContext: TDIClientContext;
FDIBuffer: TDIBuffer;
dwIoSize: DWORD );
procedure SendCompletedEvent( FClientContext: TDIClientContext;
FDIBuffer: TDIBuffer;
dwIoSize: DWORD );
procedure ProcessDataStream( FClientContext: TDIClientContext;
FDIBuffer: TDIBuffer;
dwIoSize: DWORD );
public
procedure ReadEchoPackage(FDIBuffer: TDIBuffer);
procedure WriteEchoPackage(FDIBuffer: TDIBuffer);
published
procedure AppendDisplayMsg(sMsg: String); override;
procedure AppendLogMessage(sMsg: String); override;
procedure AppendErrorLogMessage(sMsg: String); override;
procedure SendMsgToAll;
public
constructor Create(IOCompletionPort: TIOCompletionPort);
destructor Destroy; override;
end;
implementation
uses crc16, uDIMonitor, uFileLogger;
constructor TDITcpPacketEchoSocketServer.Create(IOCompletionPort: TIOCompletionPort);
begin
inherited Create(IOCompletionPort);
ZeroMemory(@FDataPakHead, SizeOf(FDataPakHead));
ZeroMemory(@FDataPakBody, SizeOf(FDataPakBody));
ZeroMemory(@FDataPakEnd, SizeOf(FDataPakEnd));
OnNewSocketEvent := NewSocketEvent;
OnCloseSocketEvent := CloseSocketEvent;
OnRecvCompletedEvent := RecvCompletedEvent;
OnSendCompletedEvent := SendCompletedEvent;
end;
destructor TDITcpPacketEchoSocketServer.Destroy;
begin
inherited Destroy;
end;
procedure TDITcpPacketEchoSocketServer.AppendDisplayMsg(sMsg: String);
begin
end;
procedure TDITcpPacketEchoSocketServer.AppendLogMessage(sMsg: String);
begin
_FileLogger.WriteLogMsg(sMsg);
end;
procedure TDITcpPacketEchoSocketServer.AppendErrorLogMessage(sMsg: String);
begin
_FileLogger.WriteLogMsg(sMsg);
end;
procedure TDITcpPacketEchoSocketServer.NewSocketEvent(FClientContext: TDIClientContext);
begin
{$IFDEF _ICOP_DEBUG}
AppendLogMessage('新客户端连接, IP地址:'+FClientContext.FRemoteIP+
' Socket ID: '+ IntToStr(FClientContext.m_KeyID)+
' m_iNumberOfActiveConnections:'+IntToStr(m_iNumberOfActiveConnections));
{$ENDIF}
end;
procedure TDITcpPacketEchoSocketServer.CloseSocketEvent(FClientContext: TDIClientContext);
begin
{
AppendDisplayMsg('客户端关闭, IP地址:'+GetRemoteIPAddr(FClientContext.FRemoteAddr)+
' Socket ID:'+ IntToStr(FClientContext.m_KeyID)); }
end;
procedure TDITcpPacketEchoSocketServer.RecvCompletedEvent( FClientContext: TDIClientContext;
FDIBuffer: TDIBuffer;
dwIoSize: DWORD );
begin
{$IFDEF _IOCP_MONITOR}
_DIMonitor.AddRecvByte(dwIoSize);
{$ENDIF}
//设置socket
FClientContext.FContextLock.Lock;
FDIBuffer.m_Socket := FClientContext.FSocket;
FClientContext.FContextLock.UnLock;
//处理数据
ProcessDataStream(FClientContext, FDIBuffer, dwIoSize);
//投递下一个Buffer
PostWSARecv(FClientContext);
end;
procedure TDITcpPacketEchoSocketServer.SendCompletedEvent( FClientContext: TDIClientContext;
FDIBuffer: TDIBuffer;
dwIoSize: DWORD );
begin
{$IFDEF _IOCP_MONITOR}
_DIMonitor.AddSendByte(dwIoSize);
{$ENDIF}
if FDIBuffer.GetUsed = dwIoSize then begin
// {$IFDEF _ICOP_DEBUG}
// AppendLogMessage('SendCompletedEvent投递完成! Key : '+IntToStr(FClientContext.m_KeyID));
// {$ENDIF}
end
else
begin
{$IFDEF _ICOP_DEBUG}
AppendLogMessage('SendCompletedEvent尚未完成! Key : '+IntToStr(FClientContext.m_KeyID));
{$ENDIF}
end;
end;
procedure TDITcpPacketEchoSocketServer.ProcessDataStream( FClientContext: TDIClientContext;
FDIBuffer: TDIBuffer;
dwIoSize: DWORD );
begin
FClientContext.FContextLock.Lock;
//读数据包
ReadEchoPackage(FDIBuffer);
FClientContext.SendBuffer.InitBuffer;
CopyMemory( Pointer(FClientContext.SendBuffer.GetBuffer),
Pointer(FDIBuffer.GetBuffer),
FDIBuffer.GetUsed );
FClientContext.SendBuffer.SetUsed(FDIBuffer.GetUsed);
FClientContext.FContextLock.UnLock;
PostWSASend(FClientContext);
end;
procedure TDITcpPacketEchoSocketServer.ReadEchoPackage(FDIBuffer: TDIBuffer);
var
sMsg: String;
m_nBufLen: Integer;
m_nPackLen: Integer;
m_nCalLen: Integer;
calCheckSum: Word;
m_nUsed: Word;
iDataLen: Integer;
m_pointPos: Pointer;
Buffer: array [0..MAX_PACKAGESIZE - 1] of Byte; //用户缓冲
begin
FSocketServerLock.Lock;
//得到Buffer长度, 暂不考虑TCP流协议造成的一个数据包未发完的情况。
//这种情况用环形Buffer拷贝,再次拼即可
m_nBufLen := FDIBuffer.GetUsed;
//包头有效情况下
if m_nBufLen> FDataPakHeadLen then begin
m_pointPos := FDIBuffer.GetBuffer;
m_nPackLen := PTDIDataPakHead(m_pointPos)^._Len;
//判断包长度是否正确
if m_nPackLen <> m_nBufLen -1 then begin
AppendLogMessage(Format('客户端Key is %d, 包长度<>m_nPackLen <> m_nBufLen -1, 包不完整,可能需要下次继续拼包.', [FDIBuffer.m_Socket]));
end;
AppendLogMessage(Format('客户端Key is %d, PDataPakHead._Head 帧头:%d.', [FDIBuffer.m_Socket, PTDIDataPakHead(m_pointPos)^._Head]));
AppendLogMessage(Format('客户端Key is %d, PDataPakHead._Len 数据长度:%d.', [FDIBuffer.m_Socket, PTDIDataPakHead(m_pointPos)^._Len]));
end
else
begin
AppendLogMessage(Format('客户端Key is %d, m_nBufLen<FDataPakHeadLen, 包不完整,可能需要下次继续拼包.', [FDIBuffer.m_Socket]));
FSocketServerLock.UnLock;
Exit;
end;
//包体有效情况下
if m_nBufLen> FDataPakHeadLen + FDataPakBodyLen then begin
m_pointPos := Pointer(LongInt(FDIBuffer.GetBuffer)+FDataPakHeadLen);
AppendLogMessage(Format('客户端Key is %d, PTTDIDataPakBody._Sing 标志位:%d.', [FDIBuffer.m_Socket, PTTDIDataPakBody(m_pointPos)^._Sing]));
AppendLogMessage(Format('客户端Key is %d, PTTDIDataPakBody._SocketKey Socket标志:%d.', [FDIBuffer.m_Socket, PTTDIDataPakBody(m_pointPos)^._SocketKey]));
AppendLogMessage(Format('客户端Key is %d, PTTDIDataPakBody._OP 操作符:%d.', [FDIBuffer.m_Socket, PTTDIDataPakBody(m_pointPos)^._OP]));
end
else
begin
AppendLogMessage(Format('客户端Key is %d, m_nBufLen<FDataPakHeadLen + FDataPakBodyLen, 包不完整,可能需要下次继续拼包.', [FDIBuffer.m_Socket]));
FSocketServerLock.UnLock;
Exit;
end;
//包尾有效情况下
if m_nBufLen> FDataPakHeadLen + FDataPakBodyLen+ FDataPakEndLen then begin
//计算数据长度
m_nCalLen := m_nBufLen- FDataPakHeadLen - FDataPakBodyLen- FDataPakEndLen;
if m_nCalLen<0 then begin
AppendLogMessage(Format('客户端Key is %d, m_nCalLen<0,可能需要下次继续拼包.', [FDIBuffer.m_Socket]));
FSocketServerLock.UnLock;
Exit;
end;
//如果计算的长度小于,封包中的长度,则以计算的为准
iDataLen := m_nPackLen;
if m_nCalLen<m_nPackLen then iDataLen := m_nCalLen;
//根据数据长度,得到数据
FillChar(Buffer, SizeOf(Buffer), 0);
//拷贝数据
m_pointPos := Pointer(LongInt(FDIBuffer.GetBuffer) + FDataPakHeadLen + FDataPakBodyLen);
CopyMemory( @Buffer[1],
m_pointPos,
iDataLen );
sMsg := pchar(@Buffer[1]);
AppendLogMessage(Format('客户端Key is %d, 数据包: %s.', [FDIBuffer.m_Socket, sMsg]));
m_pointPos := Pointer(LongInt(FDIBuffer.GetBuffer) + FDataPakHeadLen + FDataPakBodyLen +iDataLen);
AppendLogMessage(Format('客户端Key is %d, PTDIDataPakEnd._CheckSum 校验和: %d.', [FDIBuffer.m_Socket, PTDIDataPakEnd(m_pointPos)^._CheckSum]));
AppendLogMessage(Format('客户端Key is %d, PTDIDataPakEnd._SocketKey 帧结束符: %d.', [FDIBuffer.m_Socket, PTDIDataPakEnd(m_pointPos)^._End]));
m_nUsed := FDataPakHeadLen + FDataPakBodyLen +iDataLen;
calCheckSum := 0;
CalcCRC16(FDIBuffer.GetBuffer, m_nUsed, calCheckSum);
if calCheckSum = PTDIDataPakEnd(m_pointPos)^._CheckSum then begin
AppendLogMessage(Format('客户端Key is %d, PTDIDataPakEnd._CheckSum 校验和正确.', [FDIBuffer.m_Socket]));
end
else
begin
AppendLogMessage(Format('客户端Key is %d, 客户端检验和: %d, S端计算检验和: %d.', [FDIBuffer.m_Socket, PTDIDataPakEnd(m_pointPos)^._CheckSum, calCheckSum]));
end;
end
else
begin
AppendLogMessage('包体不完整,可能需要下次继续拼包.');
end;
FSocketServerLock.UnLock;
end;
procedure TDITcpPacketEchoSocketServer.WriteEchoPackage(FDIBuffer: TDIBuffer);
var
sMsg: String;
m_nBufSize, m_nUsed: Integer;
nStrLen: Integer;
begin
sMsg := 'Hello, DBIOCP. This is first echoPack example.';
nStrLen := length(sMsg);
if (nStrLen>0) then begin
m_nBufSize := nStrLen + FDataPakHeadLen + FDataPakBodyLen +FDataPakEndLen;
if m_nBufSize>MAX_PACKAGESIZE then Exit;
FDataPakHead._Head := 64; //包头帧 64
FDataPakHead._Len := m_nBufSize - SizeOf(Byte); //包长度
FDataPakBody._Sing := 16; //标置位
FDataPakBody._SocketKey := FDIBuffer.m_Socket; //Socket标志
FDataPakBody._OP := 1; //回射
//初始化
FDIBuffer.InitBuffer;
//加入包头
FDIBuffer.CreatePackage(@FDataPakHead, FDataPakHeadLen);
//加入包体
FDIBuffer.CreatePackage(@FDataPakBody, FDataPakBodyLen);
//加入数据
FDIBuffer.CreatePackage(sMsg);
//计算校验长度
m_nUsed := FDataPakHeadLen + FDataPakBodyLen + nStrLen;
//计算校验和
FDataPakEnd._CheckSum := 0;
CalcCRC16(FDIBuffer.GetBuffer, m_nUsed, FDataPakEnd._CheckSum);
FDataPakEnd._End := 16; //包尾帧 16
//加入包尾
FDIBuffer.CreatePackage(@FDataPakEnd, FDataPakEndLen);
end;
end;
procedure TDITcpPacketEchoSocketServer.SendMsgToAll;
var
m_pFreeClientContext: TDIClientContext;
m_pNextClientContext: TDIClientContext;
begin
FMapClientContextLock.Lock;
//取单链表头
m_pFreeClientContext := FMapClientContext.FClientContextList;
m_pNextClientContext := nil;
while (m_pFreeClientContext<> nil) do begin
m_pNextClientContext := m_pFreeClientContext.m_pNext;
m_pFreeClientContext.FContextLock.Lock;
m_pFreeClientContext.SendBuffer.m_Socket := m_pFreeClientContext.m_Socket;
WriteEchoPackage(m_pFreeClientContext.SendBuffer);
m_pFreeClientContext.FContextLock.UnLock;
PostWSASend(m_pFreeClientContext);
m_pFreeClientContext := m_pNextClientContext;
end;
FMapClientContextLock.UnLock;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -