📄 filetransmitunit.pas
字号:
unit FileTransmitUnit;
interface
uses
Windows,
Messages,
WinSock2,
WinSock,
PublicFunctionUnit,
vfw,
MxZLib;
const
//transmit用的参数
TF_USE_KERNEL_APC = $20;
NotifySendFileData = 27;
NotifyTermiateTransmitThread = 28;
RecvFile = 4000;
SendFile = 4001;
CreateDir = 4002;
SendDirFileList = 4003;
type
//文件传输类
TFileTransmit = Class
private
//本类内专用的结构体
RemoteSystemInfo : TRemoteSystemInfo;
//文件传输的socket
FileTransmitSocket : TSocket;
FileTransmitSocketWsaEvent : WSAEVENT;
//文件发送时,通知接收线程进行操作的
FileRecvNotifyEvent : THandle;
FileSendNotifyEvent : THandle;
//文件收发线程
RecvFileProcessTreadHandle : THandle;
SendFileProcessTreadHandle : THandle;
RecvFileProcessTreadID : DWORD;
SendFileProcessTreadID : DWORD;
//检测数据线程
DectectFileSockeThreadtHandle : THandle;
DectectFileSockeThreadID : DWORD;
//下载列表变更,线程退出等通知
MsgFileThreadNotifyEvent : THandle;
//文件数据缓冲区
FileDataBuffer : array[0..DATA_BUFSIZE - 1] of Char;
//需要发送的文件
NeedSendFileName : string;
//需要接收的文件
NeedRecvFileName : string;
//文件的接收
function RecvMyFile(const Socket : TSocket; const FileName : string; PakageDataRecvBuffer : Pointer;
const PakageLengthToRecv : LongInt; const StartWritePositon : LongInt = 0;
const RecvNotifyEvent : THandle = 0) : integer;
//文件的发送
function SendMyFile(const Socket : TSocket; const FileName : string;
const StartWritePositon : LongInt = 0) : integer;
public
constructor Create(SockAddrIn : TSockAddrIn; out Issucess : Boolean; const ServerPerIODataP : DWORD);
destructor Destroy; override;
procedure SendFileProcess;
procedure RecvFileProcess;
procedure DectectFileSockeProcess;
end;
implementation
//----------------------------TFileTransmit用到----------------------------
//文件发送线程
procedure GlobleSendFileProcess(FileTransmit : TFileTransmit); stdcall;
begin
FileTransmit.SendFileProcess;
end;
//文件接收线程
procedure GlobleRecvFileProcess(FileTransmit : TFileTransmit); stdcall;
begin
FileTransmit.RecvFileProcess;
end;
//检测socket线程
procedure GlobleDectectFileSockeProcess(FileTransmit : TFileTransmit); stdcall;
begin
FileTransmit.DectectFileSockeProcess;
end;
{--------------------------------TFileTransmit---------------------------------}
constructor TFileTransmit.Create(SockAddrIn: TSockAddrIn;
out Issucess: Boolean; const ServerPerIODataP : DWORD);
begin
Issucess := True;
FileTransmitSocket := Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (FileTransmitSocket = INVALID_SOCKET) then
begin
CloseSocket(FileTransmitSocket);
IsSucess := False;
Exit;
end;
//connect to server
if (Connect(FileTransmitSocket, SockAddrIn, SizeOf(SockAddrIn)) = SOCKET_ERROR) then
begin
CloseSocket(FileTransmitSocket);
IsSucess := False;
Exit;
end;
//将公用的结构体复制过来
MoveMemory(@RemoteSystemInfo, @PublicFunctionUnit.RemoteSystemInfo, sizeof(RemoteSystemInfo));
RemoteSystemInfo.RemoteDataType := RemoteFileData;
RemoteSystemInfo.PerIODataPointer := ServerPerIODataP;
//发送信息
SendAllTheData(FileTransmitSocket, @RemoteSystemInfo, SizeOf(RemoteSystemInfo));
//绑定新的事件
FileTransmitSocketWsaEvent := WSACreateEvent;
WSAEventSelect(FileTransmitSocket, FileTransmitSocketWsaEvent, FD_READ or FD_WRITE or FD_CLOSE);
//创建事件
FileRecvNotifyEvent := CreateEvent(nil, False, False, 'FileRecvNotifyEvent');
FileSendNotifyEvent := CreateEvent(nil, False, False, 'FileSendNotifyEvent');
MsgFileThreadNotifyEvent := CreateEvent(nil, False, False, 'MsgFileThreadNotifyEvent');
//创建线程
if Issucess then
begin
RecvFileProcessTreadHandle := CreateThread(nil, 0, @GlobleRecvFileProcess,
Pointer(Self), 0, RecvFileProcessTreadID);
SendFileProcessTreadHandle := CreateThread(nil, 0, @GlobleSendFileProcess,
Pointer(Self), 0, SendFileProcessTreadID);
DectectFileSockeThreadtHandle := CreateThread(nil, 0, @GlobleRecvFileProcess,
Pointer(Self), 0, DectectFileSockeThreadID);
CloseHandle(DectectFileSockeThreadtHandle);
end;
end;
//free掉类
destructor TFileTransmit.Destroy;
begin
//关闭线程
if RecvFileProcessTreadID <> 0 then
begin
TerminateThread(RecvFileProcessTreadHandle, 0);
CloseHandle(RecvFileProcessTreadHandle);
end;
if SendFileProcessTreadID <> 0 then
begin
TerminateThread(SendFileProcessTreadHandle, 0);
CloseHandle(SendFileProcessTreadHandle);
end;
//取消绑定
WSAEventSelect(FileTransmitSocket, 0, 0);
WSACloseEvent(FileTransmitSocketWsaEvent);
//关闭socket
ShutDown(FileTransmitSocket, SD_BOTH);
CloseSocket(FileTransmitSocket);
//关闭事件
CloseHandle(FileRecvNotifyEvent);
CloseHandle(FileSendNotifyEvent);
CloseHandle(MsgFileThreadNotifyEvent);
inherited;
end;
//检测文件socket的状态
procedure TFileTransmit.DectectFileSockeProcess;
var
myWSANETWORKEVENTS : WSANETWORKEVENTS;
WaitResult : DWord;
begin
while True do
begin
WaitResult := WSAWaitForMultipleEvents(1, @FileTransmitSocketWsaEvent, False, 100, False);
//如果超时,则继续下一个循环
if WaitResult >= WSA_WAIT_TIMEOUT then
begin
Continue;
end;
//查询网络事件类型
ZeroMemory(@myWSANETWORKEVENTS, SizeOf(myWSANETWORKEVENTS));
WSAEnumNetworkEvents(FileTransmitSocket, FileTransmitSocketWsaEvent, @myWSANETWORKEVENTS);
//数据接收
if (myWSANETWORKEVENTS.lNetWorkEvents and FD_READ) > 0 then
begin
if myWSANETWORKEVENTS.iErrorCode[FD_READ_BIT] <> 0 then
begin
Continue;
end;
SetEvent(FileRecvNotifyEvent);
end;
//数据发送
if (myWSANETWORKEVENTS.lNetWorkEvents and FD_WRITE) > 0 then
begin
if myWSANETWORKEVENTS.iErrorCode[FD_WRITE_BIT] <> 0 then
begin
Continue;
end;
SetEvent(FileSendNotifyEvent);
end;
//远程socket关闭通知
if (myWSANETWORKEVENTS.lNetWorkEvents and FD_CLOSE) > 0 then
begin
ShutDown(FileTransmitSocket, SD_SEND);
Break;
end;
end;
end;
//接收文件
procedure TFileTransmit.RecvFileProcess;
var
Msg : TMsg;
myDataHeaderInfo : TDataHeaderInfo;
myInterChangeHeader : TInterChangeHeader;
ActuallySentSizePerPakage : LongInt;
FileName : array[0.. DATA_BUFSIZE - 1] of Char;
MakeDirPath, DirFileList : string;
begin
//创建一个消息队列
PeekMessage(Msg, 0, $400, $400, PM_NOREMOVE);
Sleep(5);
while true do
begin
//接收发来的线程消息
if (PeekMessage(Msg, 0, TerminateNotifyMessage, TerminateNotifyMessage, PM_REMOVE)) then
begin
case Msg.wParam of
NotifyTermiateTransmitThread:
begin
//通知发送者,线程结束
SetEvent(MsgFileThreadNotifyEvent);
Break;
end;
end;
end;
//先接收8个字节,来判断接下来的文件大小
if RecvAllData(FileTransmitSocket, @myDataHeaderInfo, SizeOf(myDataHeaderInfo),
ActuallySentSizePerPakage, FileRecvNotifyEvent) = SOCKET_ERROR then
begin
sleep(20);
Continue;
end;
//再接收命令数据描述头
if RecvAllData(FileTransmitSocket, @myInterChangeHeader, SizeOf(myInterChangeHeader),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -