📄 iocpunit.pas
字号:
unit IocpUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, Buttons, ComCtrls, winsock2, winsock, IocpHerder,
mssock, SyncObjs, Lzo, MxZLib, PublicFunctionUnit, FileAndClientInfoCtrlUnit,
VideoFormUnit, DisplayRemoteScreenUnit;
type
//工作者线程类
Tworkerthread = class(TThread)
private
mythreadId : integer;
PHandledata : PPerHandleData;
OfflineSocket : Tsocket;
procedure ListViewAddItem;
procedure ListViewDeletItem;
protected
procedure Execute; override;
function HandleData(var lp_Io: PPerHandleData; flag : TIocpCompleteState) : Boolean;
function DataAction(lp_Io : PPerHandleData) : Boolean;
public
constructor create(CreateSuspended : Boolean; Id : integer); overload;
end;
//新增acceptex的类
TAcceptexThread = class(TThread)
private
msg : string;
acceptcount : integer;
function postacceptEx(count : Integer) : Boolean;
function postoneacceptEx() : Boolean;
procedure ShowMsg;
protected
procedure Execute; override;
public
constructor create(CreateSuspended : Boolean; acceptCnt : integer); overload;
end;
var
lpAcceptEx : TAcceptEx;
implementation
uses MainWindow;
{--------------------------------Tworkerthread---------------------------------}
constructor Tworkerthread.create(CreateSuspended: Boolean; Id: integer);
begin
Create(CreateSuspended);
priority := tpTimeCritical;
mythreadId := ID;
FreeOnTerminate := True;
end;
(*--------------------以下主要是进行数据的接收和处理操作的--------------------*)
procedure Tworkerthread.Execute;
var
PHandleData : PPerHandleData;
lpKey : DWORD;
nRet : Integer;
dwBytes : DWORD;
bRet : Boolean;
hRet : Thandle;
tmpIPStr : string;
myDisplayRemoteScreen : TDisplayRemoteScreen;
myVideoForm : TVideoForm;
myFileAndInfoCtrlForm : TFileAndInfoCtrlForm;
begin
//初始化
PHandleData := nil;
dwBytes := 0;
//循环查询I/O完成队列
while (TRUE) do
begin
bRet := GetQueuedCompletionStatus(g_CompletionPort, dwBytes, lpKey, POverlapped(PHandleData), INFINITE);
//接收到服务器关闭事件
if Cardinal(PhandleData) = SHUTDOWN_FLAG then
begin
Break;
end;
//函数返回错误
if (bRet = False) or (PHandleData = nil) then
begin
Continue;
end;
//client退出了,需要释放相关内存
if (PHandleData^.operType <> IO_ACCEPT) and (dwBytes = 0) then
begin
case PHandleData^.RemoteSystemInfo.RemoteDataType of
MainSocketData:
begin
//屏传
if PHandleData^.AllCtrlInstance.CapScreenInstance <> 0 then
begin
myDisplayRemoteScreen := TDisplayRemoteScreen(PHandleData^.AllCtrlInstance.CapScreenInstance);
myDisplayRemoteScreen.Caption := myDisplayRemoteScreen.CaptionStr + '远程主机已下线';
myDisplayRemoteScreen.MainClientSocketIP_IO := nil;
end;
//视频
if PHandleData^.AllCtrlInstance.CapVideoInstance <> 0 then
begin
myVideoForm := TVideoForm(PHandleData^.AllCtrlInstance.CapVideoInstance);
myVideoForm.Caption := myVideoForm.CaptionStr + '远程主机已下线';
myVideoForm.MainClientSocketIP_IO := nil;
//在这里可以考虑添加发送关闭的消息
end;
//系统信息和文件传输
if PHandleData^.AllCtrlInstance.GetSystemInfoInstance <> 0 then
begin
myFileAndInfoCtrlForm := TFileAndInfoCtrlForm(PHandleData^.AllCtrlInstance.GetSystemInfoInstance);
myFileAndInfoCtrlForm.Caption := myFileAndInfoCtrlForm.CaptionStr + '远程主机已下线';
myFileAndInfoCtrlForm.MainClientSocketIP_IO := nil;
//在这里可以考虑添加发送关闭的消息
end;
//由于是发送到主线程里面进行执行的,因此不需要同步的
self.OfflineSocket := PHandleData^.Socket;
self.Synchronize(self.ListViewDeletItem);
//关闭socket
shutdown(PHandleData^.Socket, SD_BOTH);
CloseSocket(PHandleData^.Socket);
//释放结构内存资源
FreeOverlappedPlus(PHandledata);
end;
RemoteScreenData,
RemoteVideoData,
RemoteAudioData,
GetSystemInfoData,
RemoteFileData:
begin
//关闭socket
shutdown(PHandleData^.Socket, SD_BOTH);
CloseSocket(PHandleData^.Socket);
//释放结构内存资源
FreeOverlappedPlus(PHandledata);
end;
end;
Continue;
end;
//判断操作类型
case PHandleData^.operType of
IO_ACCEPT:
begin
//更新新连接进来的socket的选项
//使PHandledata.Socket具有和g_listensocket相同的属性
nRet := setsockopt(PHandledata.Socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
Pansichar(@g_listensocket), sizeof(g_listensocket));
if(nRet = SOCKET_ERROR) then
begin
closesocket(PHandledata.Socket);
//应该在这里释放资源,否则可能造成资源泄露
FreeOverlappedPlus(PHandleData);
Continue;
end;
PHandleData^.IsInformed := False;
//得到client的IP
ZeroMemory(@PHandleData^.ExternalIPaddressString[0], sizeof(PHandleData^.ExternalIPaddressString));
tmpIPStr := Format('%d.%d.%d.%d', [Byte(PHandledata^.buffer[42]),
Byte(PHandledata^.buffer[43]),
Byte(PHandledata^.buffer[44]),
Byte(PHandledata^.buffer[45])]);
CopyMemory(@PHandleData^.ExternalIPaddressString[0], Pchar(tmpIPStr), length(tmpIPStr));
//将新的socket与完成端口连接
hRet := CreateIoCompletionPort(THANDLE(PHandledata^.Socket),
g_CompletionPort, 0, 0);
if (hRet = 0) then
begin
closesocket(PHandledata.Socket);
Continue;
end;
//判断是否连接来以后,随即又发送了数据
if (dwbytes > 0) then
begin
PHandledata^.ptrBuffer^.len := dwbytes;
HandleData(PHandledata, IOCP_COMPLETE_ACCEPT_READ);
bRet := DataAction(PHandledata);
if (bRet = FALSE) then Continue;
end
else
begin
HandleData(PHandledata, IOCP_COMPLETE_ACCEPT);
bRet := DataAction(PHandledata);
if (bRet = FALSE) then Continue;
end;
end; // IO_ACCEPT case end
//省略...~~
end; //case end
end; //while end
self.Terminate;
end;
//数据处理过程
function Tworkerthread.HandleData(var lp_Io : PPerHandleData; flag : TIocpCompleteState): Boolean;
var
myDisplayRemoteScreen : TDisplayRemoteScreen;
myVideoForm : TVideoForm;
myFileAndInfoCtrlForm : TFileAndInfoCtrlForm;
tmplp_Io : PPerHandleData;
begin
Result := True;
case flag of
IOCP_COMPLETE_ACCEPT:
begin
//初始化,用来接受client发来的信息
InitIoContext(lp_io);
lp_io.operType := IO_READ;
end;
IOCP_COMPLETE_READ:
begin
// 如果是没IsInformed的数据,那么就是远程主机信息的数据
if not lp_Io^.IsInformed then
begin
//设置数据接收缓冲区的参数,增加接收计数
lp_io^.ptrBuffer^.buf := PChar(DWORD(lp_io^.ptrBuffer^.buf) + lp_io^.ptrBuffer^.len);
lp_io^.ptrBuffer^.len := Sizeof(TDataHeaderInfo) + Sizeof(TRemoteSystemInfo)
- (DWORD(lp_io^.ptrBuffer^.buf) - DWORD(@lp_io^.Buffer[0]));
//如果数据超过了结构体的大小,则就进行处理
if DWORD(lp_io^.ptrBuffer^.buf) - DWORD(@lp_io^.Buffer[0]) >= Sizeof(TDataHeaderInfo)
+ Sizeof(TRemoteSystemInfo) then
begin
//从buf里面拷贝数据出来
CopyMemory(@lp_io^.RemoteSystemInfo, @lp_io^.Buffer[0 + Sizeof(TDataHeaderInfo)], Sizeof(TRemoteSystemInfo));
lp_Io^.IsInformed := True;
case lp_Io^.RemoteSystemInfo.RemoteDataType of
MainSocketData:
begin
//接受心跳
lp_io^.IsAlive := True;
Self.PHandledata := lp_io;
//线程同步的,不需要互斥
self.Synchronize(self.ListViewAddItem);
end;
RemoteScreenData:
begin
//取得主sokcet的单io数据指针
tmplp_Io := PPerHandleData(lp_Io^.RemoteSystemInfo.PerIODataPointer);
myDisplayRemoteScreen :=
TDisplayRemoteScreen(tmplp_Io^.AllCtrlInstance.CapScreenInstance);
//将类实例指针赋值给本类的内的指针
lp_Io^.AllCtrlInstance.CapScreenInstance :=
tmplp_Io^.AllCtrlInstance.CapScreenInstance;
//赋值给本类的socket记录
myDisplayRemoteScreen.ClientSocket := lp_Io^.Socket;
//赋值给本类内的主socket的单io记录
myDisplayRemoteScreen.MainClientSocketIP_IO := tmplp_Io;
//将单io数据赋值给类,以便进行释放
myDisplayRemoteScreen.SubClientSocketIP_IO := lp_Io;
end;
RemoteVideoData:
begin
//取得主sokcet的单io数据指针
tmplp_Io := PPerHandleData(lp_Io^.RemoteSystemInfo.PerIODataPointer);
myVideoForm :=
TVideoForm(tmplp_Io^.AllCtrlInstance.CapVideoInstance);
//将类实例指针赋值给本类的内的指针
lp_Io^.AllCtrlInstance.CapVideoInstance :=
tmplp_Io^.AllCtrlInstance.CapVideoInstance;
//赋值给本类的socket记录
myVideoForm.ClientSocket := lp_Io^.Socket;
//赋值给本类内的主socket的单io记录
myVideoForm.MainClientSocketIP_IO := tmplp_Io;
//将单io数据赋值给类,以便进行释放
myVideoForm.SubClientSocketIP_IO := lp_Io;
end;
RemoteFileData:
begin
end;
GetSystemInfoData:
begin
//取得主sokcet的单io数据指针
tmplp_Io := PPerHandleData(lp_Io^.RemoteSystemInfo.PerIODataPointer);
myFileAndInfoCtrlForm :=
TFileAndInfoCtrlForm(tmplp_Io^.AllCtrlInstance.GetSystemInfoInstance);
//将类实例指针赋值给本类的内的指针
lp_Io^.AllCtrlInstance.GetSystemInfoInstance :=
tmplp_Io^.AllCtrlInstance.GetSystemInfoInstance;
//赋值给本类的socket记录
myFileAndInfoCtrlForm.ClientSocket := lp_Io^.Socket;
//赋值给本类内的主socket的单io记录
myFileAndInfoCtrlForm.MainClientSocketIP_IO := tmplp_Io;
//将单io数据赋值给类,以便进行释放
myFileAndInfoCtrlForm.SubClientSocketIP_IO := lp_Io;
end;
RemoteAudioData:
begin
end;
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -