📄 iocpherder.pas
字号:
unit IocpHerder;
interface
uses
Windows, Messages, WinSock2, Classes, Controls, PublicFunctionUnit,
SysUtils, mssock, forms, lzo, MxZLib;
{$DEFINE _MiniLzo}
//屏传数据处理函数
procedure DealRemoteScreenData(var lp_Io : PPerHandleData);
//视频数据处理
procedure DealRemoteVideoData(var lp_Io : PPerHandleData);
//文件数据处理函数
procedure DealRemoteFileData(var lp_Io : PPerHandleData;
const FileDataBuffer : Pointer = nil; const DataLen : integer = 0);
//文件列表数据处理函数
procedure DealRemoteFileListData(var lp_Io : PPerHandleData);
const
SHUTDOWN_FLAG = $FFFFFFFF;
CWaitTime = 300;
var
//iocp使用的一些变量
WSData : TWSAData;
g_CompletionPort : THandle;
g_listensocket : TSocket;
eventarray : array [0..1] of Thandle; //上面两个事件的集合
g_hAcceptThread : Thandle; //接受线程,主要是当lpacceptex用完后,发出新的lpacceptex调用
g_hWorkerThreads : array of Thandle; //工作者线程数组
g_workerthreadcount : Cardinal; //工作者线程数量
g_VariableAccessSemaphore : TRTLCriticalSection; //变量访问你控制的临界区
implementation
uses DisplayRemoteScreenUnit, MainWindow, VideoFormUnit, FileAndClientInfoCtrlUnit; //
//主要是处理屏传的时候,收到的数据包里面包含了多了数据帧---粘包处理
function ProcessFirstPackegeData(
var lp_Io : PPerHandleData;
const SubDataBuffer : Pointer;
const SubDataLen : integer;
var tmpDataBuffer : TtmpBuf;
var RemoteCmpedFrameData : Pointer;
var RemoteUnCmpedFrameData : Pointer;
const RemoteCmpedFrameArray : array of Char;
const RemoteUnCmpedFrameArray : array of Char;
const FormHandle : THandle;
const CmpFrameDataType : Byte = 0;//0:无压缩,1:lzo压缩, 2:MSH263+压缩
const MsgDealDataOkNotifyEvent : THandle = 0;
const IsClosing : Boolean = False
) : Boolean;
begin
//省略...~~
end;
//屏传数据处理函数
procedure DealRemoteScreenData(var lp_Io : PPerHandleData);
var
RemainDataSize : Word;
SubDataBuffer : Pointer;
SubDataLen : integer;
UnCmpFrameDataLen : longint;
myDisplayRemoteScreen : TDisplayRemoteScreen;
WaitTime : DWORD;
begin
//获取屏传类实例
myDisplayRemoteScreen := TDisplayRemoteScreen(lp_Io^.AllCtrlInstance.CapScreenInstance);
//如果是开头数据,则直接子函数进行处理
if lp_io^.RemoteDataInfo.DataHeaderInfo.CompressedDataSize = 0 then
begin
SubDataBuffer := lp_io^.ptrBuffer.buf;
SubDataLen := lp_io^.ptrBuffer.len;
//调用处理子函数
if not ProcessFirstPackegeData(lp_Io, SubDataBuffer, SubDataLen,
myDisplayRemoteScreen.tmpDataBuffer,
myDisplayRemoteScreen.RemoteCmpedFrameData,
myDisplayRemoteScreen.RemoteUnCmpedFrameData,
myDisplayRemoteScreen.RemoteCmpedFrameArray,
myDisplayRemoteScreen.RemoteUnCmpedFrameArray,
myDisplayRemoteScreen.Handle,
1, //lzo(zlib) 压缩
myDisplayRemoteScreen.MsgDealDataOkNotifyEvent,
myDisplayRemoteScreen.IsClosing
)
then
begin
lp_Io^.IsUsed := False;
Exit;
end;
end
//如果非开头的数据,并且帧内存区域里面的数据+刚收到的数据还是不足一帧数据
//则直接将刚收到的数据拷贝进帧内存区域------------------------------------(1)
else if lp_io^.RemoteDataInfo.FilledDataLength + lp_io^.ptrBuffer.len <
lp_io^.RemoteDataInfo.DataHeaderInfo.CompressedDataSize then
begin
//将数据拷贝进帧内存区
CopyMemory(Pointer(DWORD(myDisplayRemoteScreen.RemoteCmpedFrameData) +
lp_io^.RemoteDataInfo.FilledDataLength),
lp_io^.ptrBuffer.buf, lp_io^.ptrBuffer.len);
//增加帧数据内存区的已填充的计数
Inc(lp_io^.RemoteDataInfo.FilledDataLength, lp_io^.ptrBuffer.len);
//如果是屏传,则设置屏传窗口caption,显示传输速度
if lp_io^.RemoteSystemInfo.RemoteDataType = RemoteScreenData then
begin
myDisplayRemoteScreen := TDisplayRemoteScreen(lp_io^.AllCtrlInstance.CapScreenInstance);
//设置屏传标题
SetWindowText(myDisplayRemoteScreen.Handle,
Pchar(myDisplayRemoteScreen.CaptionStr + ',' +
IntTostr(lp_io^.RemoteDataInfo.FilledDataLength * 100 div
lp_io^.RemoteDataInfo.DataHeaderInfo.CompressedDataSize) + '%'));
end;
end
else
//如果(1)的条件不成立,说明已经足够一帧数据了,则进行处理
begin
RemainDataSize := lp_io^.RemoteDataInfo.FilledDataLength + lp_io^.ptrBuffer.len -
lp_io^.RemoteDataInfo.DataHeaderInfo.CompressedDataSize;
//拷贝数据
if lp_io^.RemoteDataInfo.FilledDataLength <
lp_io^.RemoteDataInfo.DataHeaderInfo.CompressedDataSize then
begin
CopyMemory(Pointer(DWORD(myDisplayRemoteScreen.RemoteCmpedFrameData) +
lp_io^.RemoteDataInfo.FilledDataLength),
lp_io^.ptrBuffer.buf, lp_io^.RemoteDataInfo.DataHeaderInfo.CompressedDataSize -
lp_io^.RemoteDataInfo.FilledDataLength);
end;
//解压并进行数据处理
{$IFDEF _MiniLzo}
UnCmpFrameDataLen := lp_io^.RemoteDataInfo.DataHeaderInfo.UnCompressedDataSize;
//申请解压内存
GetMyMem(UnCmpFrameDataLen, myDisplayRemoteScreen.RemoteUnCmpedFrameData,
myDisplayRemoteScreen.RemoteUnCmpedFrameArray);
DecompressData(myDisplayRemoteScreen.RemoteCmpedFrameData,
lp_io^.RemoteDataInfo.DataHeaderInfo.CompressedDataSize,
myDisplayRemoteScreen.RemoteUnCmpedFrameData);
{$ELSE}
//Zlib解压
UnCmpFrameDataLen := lp_io^.RemoteDataInfo.DataHeaderInfo.UnCompressedDataSize;
//申请解压内存
GetMyMem(UnCmpFrameDataLen, myDisplayRemoteScreen.RemoteUnCmpedFrameData,
myDisplayRemoteScreen.RemoteUnCmpedFrameArray);
ZDecompress(myDisplayRemoteScreen.RemoteCmpedFrameData,
lp_io^.RemoteDataInfo.DataHeaderInfo.CompressedDataSize,
myDisplayRemoteScreen.RemoteUnCmpedFrameData,
UnCmpFrameDataLen);
{$ENDIF}
//通知主窗口,新的数据帧已经到了,lParam就是数据本身的指针
if IsWindow(myDisplayRemoteScreen.Handle) then
begin
PostMessage(myDisplayRemoteScreen.Handle, WM_DealDataMsg,
LOWORD(DWORD(myDisplayRemoteScreen.RemoteCmpedFrameData)),
HIWORD(DWORD(myDisplayRemoteScreen.RemoteCmpedFrameData)));
//等待数据出来完毕
WaitTime := WaitForSingleObject(myDisplayRemoteScreen.MsgDealDataOkNotifyEvent, CWaitTime);
//如果超时或者出错,则返回错误
if (WaitTime = WAIT_TIMEOUT) or (WaitTime = WAIT_FAILED) then
begin
if myDisplayRemoteScreen.IsClosing then
begin
lp_Io^.IsUsed := False;
Exit;
end;
end;
end;
//释放屏幕数据的内存
if myDisplayRemoteScreen.RemoteCmpedFrameData <> nil then
begin
FreeMyMem(myDisplayRemoteScreen.RemoteCmpedFrameData,
myDisplayRemoteScreen.RemoteCmpedFrameArray);
end;
if myDisplayRemoteScreen.RemoteUnCmpedFrameData <> nil then
begin
FreeMyMem(myDisplayRemoteScreen.RemoteUnCmpedFrameData,
myDisplayRemoteScreen.RemoteUnCmpedFrameArray);
end;
//清空缓冲区,复位数据记录
ZeroMemory(@myDisplayRemoteScreen.tmpDataBuffer, sizeof(myDisplayRemoteScreen.tmpDataBuffer));
ZeroMemory(@lp_io^.RemoteDataInfo, sizeof(lp_io^.RemoteDataInfo));
//如果还有剩余的数据,则调用子函数进行处理
if RemainDataSize > 0 then
begin
SubDataBuffer := Pointer(longint(lp_io^.ptrBuffer.buf) +
longint(lp_io^.ptrBuffer.len) - RemainDataSize);
SubDataLen := RemainDataSize;
//调用处理子函数
if not ProcessFirstPackegeData(lp_Io, SubDataBuffer, SubDataLen,
myDisplayRemoteScreen.tmpDataBuffer,
myDisplayRemoteScreen.RemoteCmpedFrameData,
myDisplayRemoteScreen.RemoteUnCmpedFrameData,
myDisplayRemoteScreen.RemoteCmpedFrameArray,
myDisplayRemoteScreen.RemoteUnCmpedFrameArray,
myDisplayRemoteScreen.Handle,
1, //lzo(zlib) 压缩
myDisplayRemoteScreen.MsgDealDataOkNotifyEvent,
myDisplayRemoteScreen.IsClosing
)
then
begin
lp_Io^.IsUsed := False;
Exit;
end;
end
end;
//重置接收缓冲区的大小
lp_io.ptrBuffer.len := MAX_BUFSIZE;
end;
//视频数据处理函数
procedure DealRemoteVideoData(var lp_Io : PPerHandleData);
var
RemainDataSize : Word;
SubDataBuffer : Pointer;
SubDataLen : integer;
//视频类指针
myVideoForm : TVideoForm;
WaitTime : DWORD;
begin
//取得视频类指针
myVideoForm := TVideoForm(lp_Io^.AllCtrlInstance.CapVideoInstance);
//如果是开头数据,则直接子函数进行处理
if lp_io^.RemoteDataInfo.DataHeaderInfo.CompressedDataSize = 0 then
begin
SubDataBuffer := lp_io^.ptrBuffer.buf;
SubDataLen := lp_io^.ptrBuffer.len;
//调用处理子函数,接受视频流
if not ProcessFirstPackegeData(lp_Io, SubDataBuffer, SubDataLen,
myVideoForm.tmpDataBuffer,
myVideoForm.RemoteCmpedFrameData,
myVideoForm.RemoteUnCmpedFrameData,
myVideoForm.RemoteCmpedFrameArray,
myVideoForm.RemoteCmpedFrameArray,
myVideoForm.Handle,
2, //msh263 压缩
myVideoForm.MsgDealDataOkNotifyEvent,
myVideoForm.IsClosing
)
then
begin
lp_Io^.IsUsed := False;
Exit;
end;
end
//如果非开头的数据,并且帧内存区域里面的数据+刚收到的数据还是不足一帧数据
//则直接将刚收到的数据拷贝进帧内存区域------------------------------------(1)
else if lp_io^.RemoteDataInfo.FilledDataLength + lp_io^.ptrBuffer.len <
lp_io^.RemoteDataInfo.DataHeaderInfo.CompressedDataSize then
begin
//将数据拷贝进帧内存区
CopyMemory(Pointer(DWORD(myVideoForm.RemoteCmpedFrameData) + lp_io^.RemoteDataInfo.FilledDataLength),
lp_io^.ptrBuffer.buf, lp_io^.ptrBuffer.len);
//增加帧数据内存区的已填充的计数
Inc(lp_io^.RemoteDataInfo.FilledDataLength, lp_io^.ptrBuffer.len);
end
else
//如果(1)的条件不成立,说明已经足够一帧数据了,则进行处理
begin
RemainDataSize := lp_io^.RemoteDataInfo.FilledDataLength + lp_io^.ptrBuffer.len -
lp_io^.RemoteDataInfo.DataHeaderInfo.CompressedDataSize;
//拷贝数据
if lp_io^.RemoteDataInfo.FilledDataLength <
lp_io^.RemoteDataInfo.DataHeaderInfo.CompressedDataSize then
begin
CopyMemory(Pointer(DWORD(myVideoForm.RemoteCmpedFrameData) + lp_io^.RemoteDataInfo.FilledDataLength),
lp_io^.ptrBuffer.buf, lp_io^.RemoteDataInfo.DataHeaderInfo.CompressedDataSize -
lp_io^.RemoteDataInfo.FilledDataLength);
end;
//如果是视频流,则就进行解压
if lp_io^.RemoteDataInfo.DataHeaderInfo.DataType = NOCMDReplay then
begin
//解压并进行数据处理
if myVideoForm.m_CodecMgr.DecodeVideoData(PChar(myVideoForm.RemoteCmpedFrameData),
lp_io^.RemoteDataInfo.DataHeaderInfo.CompressedDataSize,
PChar(myVideoForm.RemoteCmpedFrameData), nil, 0) then
begin
PostMessage(myVideoForm.Handle, WM_TCP_VIDEO_DATAISOK,
LOWORD(DWORD(myVideoForm.RemoteCmpedFrameData)),
HIWORD(DWORD(myVideoForm.RemoteCmpedFrameData)));
//等待数据出来完毕
WaitTime := WaitForSingleObject(myVideoForm.MsgDealDataOkNotifyEvent, CWaitTime);
//如果超时或者出错,则返回错误
if (WaitTime = WAIT_TIMEOUT) or (WaitTime = WAIT_FAILED) then
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -