procedure TSendThread.HandleException;
var
E: Exception;
begin
E := Exception(ExceptObject);
PostMessage(Form1.Handle, WM_PROGRESS, 3, Integer(PChar(E.Message)));
end;
procedure TSendThread.Execute;
procedure Check(Value: Boolean);
begin
if Value then
raise ESocketError.Create('Socket send error');
end;
function TSendThread.Send(var Buffer; Count: Integer): Integer;
var
FDSet: TFDSet;
TimeVal: TTimeVal;
RetVal: Integer;
begin
if FSocket.SocketHandle <> INVALID_SOCKET then
begin
Result := FSocket.SendBuf(Buffer, Count);
if Result <> Count then
raise ESocketError.Create('Socket send error.');
Result := -1;
FD_ZERO(FDSet);
FD_SET(FSocket.SocketHandle, FDSet);
TimeVal.tv_sec := 10;
TimeVal.tv_usec := 0;
RetVal := select(0, @FDSet, nil, nil, @TimeVal);
if RetVal > 0 then
begin
RetVal := FSocket.ReceiveBuf(Result, SizeOf(Result));
if RetVal <> SizeOf(Result) then
raise ESocketError.Create('Socket read error.');
end;
end
else
raise ESocketError.Create('Socket invalid');
end;
{ TForm1 }
procedure TForm1.SendProgress;
begin
case msg.WParam of
0:
begin
Inc(FSendCount, msg.LParam);
Caption := FormatFloat('###,###,###.##', FSendCount);
end;
1: FSendCount := 0;
2: Caption := 'File send over.';
3: Caption := 'Error: ' + PChar(msg.LParam);
end;
end;
procedure TForm1.ThreadTerminate(Sender: TObject);
begin
FThread := nil;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if not Assigned(FThread) then
begin
ClientSocket1.Close;
Sleep(10);
ClientSocket1.Host := Edit1.Text;
ClientSocket1.ClientType := ctBlocking;
ClientSocket1.Open;
if not FileExists(Edit2.Text) then
raise Exception.CreateFmt('File: %s not exists', [Edit2.Text]);
FThread := TSendThread.Create(ClientSocket1.Socket, Edit2.Text);
FThread.OnTerminate := ThreadTerminate;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if Assigned(FThread) then
FThread.Terminate;
end;
end.
//unit1.dfm
object Form1: TForm1
Left = 197
Top = 143
Width = 404
Height = 176
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 72
Top = 112
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object Edit1: TEdit
Left = 72
Top = 48
Width = 233
Height = 21
TabOrder = 1
Text = '192.168.1.16'
end
object Edit2: TEdit
Left = 72
Top = 80
Width = 233
Height = 21
TabOrder = 2
Text = 'c:\temp\a.rar'
end
object Button2: TButton
Left = 208
Top = 112
Width = 75
Height = 25
Caption = 'Stop Send'
TabOrder = 3
OnClick = Button2Click
end
object ClientSocket1: TClientSocket
Active = False
ClientType = ctBlocking
Port = 211
Left = 176
Top = 112
end
end
{ TClientThread }
procedure TClientThread.HandleException;
var
E: Exception;
begin
E := Exception(ExceptObject);
if not Assigned(E) or (E is EAbort) then Exit;
if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
PostMessage(Form2.Handle, WM_PROGRESS, 3, Integer(PChar(E.Message)));
end;
type
TFileBlock = packed record
FileName: array [0..100] of Char;
FileSize: Integer;
CRC32: LongWord; // reserved
end;
procedure TClientThread.ClientExecute;
procedure Check(Value: Boolean; msg: string);
begin
if Value then raise Exception.Create(msg);
end;
function WaitForData(Timeout: Integer = 30): Boolean;
var
FDSet: TFDSet;
TimeVal: TTimeVal;
begin
TimeVal.tv_sec := Timeout;
TimeVal.tv_usec := 1;
FD_ZERO(FDSet);
FD_SET(ClientSocket.SocketHandle, FDSet);
Result := select(0, @FDSet, nil, nil, @TimeVal) > 0;
end;
function ReceiveBuf(var Buffer; Count: Integer): Integer;
begin
Result := -1;
if not WaitForData then Exit;
Result := ClientSocket.ReceiveBuf(Buffer, Count);
end;
function SendBuf(var Buffer; Count: Integer): Integer;
begin
Result := ClientSocket.SendBuf(Buffer, Count)
end;
var
hFile: THandle;
Buffer: Pointer;
FileName: string;
FileInfo: TFileBlock;
Size, BufSize, RetVal, Count, RecvCount: Integer;
begin
BufSize := 10240 ;
FileName := Format('host: %s begin send file', [ClientSocket.RemoteAddress]);
PostMessage(Form2.Handle, WM_PROGRESS, 0, Integer(PChar(FileName)));
try
RetVal := SizeOf(FileInfo);
Check(ReceiveBuf(FileInfo, RetVal) <> RetVal, 'Socket read error');
FileName := ExtractFilePath(ParamStr(0)) + 'File\' + FileInfo.FileName;
hFile := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE,
0, nil, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
try
Size := FileSeek(hFile, 0, Ord(soEnd));
Check(SendBuf(Size, SizeOf(Size)) <> SizeOf(Size), 'Socket send error');
Dec(FileInfo.FileSize, Size);
GetMem(Buffer, BufSize);
try
while ClientSocket.Connected and (FileInfo.FileSize > 0) do
begin
RecvCount := 0;
if not WaitForData then break;
RetVal := ClientSocket.ReceiveBuf(Count, SizeOf(Count));
if RetVal = 0 then break;
Check(RetVal <> SizeOf(Count), 'Socket read error');
RetVal := ClientSocket.ReceiveBuf(Buffer^, Count);
while (RetVal > 0) do
begin
Check(FileWrite(hFile, Buffer^, RetVal) <> RetVal, 'File write error');
Dec(FileInfo.FileSize, RetVal);
Inc(RecvCount, RetVal);
if RecvCount >= Count then break;
RetVal := ClientSocket.ReceiveBuf(Buffer^, Count - RecvCount);
end;
if RecvCount > 0 then
begin
RetVal := SendBuf(RecvCount, SizeOf(RecvCount));
Check((RetVal = 0) or (RetVal <> SizeOf(Integer)),
Format('Socket send error: RecvCount: %d', [RecvCount]));
end;
end;
PostMessage(Form2.Handle, WM_PROGRESS, 2, 0);
finally
ClientSocket.Close;
FreeMem(Buffer);
end;
finally
FileClose(hFile);
end;
except
ClientSocket.Close;
HandleException;
end;
end;
{ TForm2 }
procedure TForm2.Progress;
begin
case msg.WParam of
0: Memo1.Lines.Add('Message: ' + PChar(msg.LParam));
2: Memo1.Lines.Add('recv over');
3: Memo1.Lines.Add('Error: ' + PChar(msg.LParam));
end;
end;
procedure TForm2.ServerSocket1GetThread;
begin
SocketThread := TClientThread.Create(False, ClientSocket);
end;
procedure TForm2.SocketEvent;
var
Reuse: Integer;
begin
if Assigned(FSocketEvent) then
FSocketEvent(Sender, Socket, SocketEvent);
if SocketEvent = seLookUp then
begin
Reuse := 1;
if Socket.SocketHandle <> INVALID_SOCKET then
setsockopt(Socket.SocketHandle, SOL_SOCKET, SO_REUSEADDR,
PChar(@Reuse), SizeOf(Reuse));
end;
end;
procedure TForm2.FormCreate;
var
Dir: string;
begin
FSocketEvent := ServerSocket1.Socket.OnSocketEvent;
ServerSocket1.Socket.OnSocketEvent := SocketEvent;
ServerSocket1.Active := True;
Dir := ExtractFilePath(ParamStr(0)) + 'File\';
if not DirectoryExists(Dir) then CreateDir(Dir);
end;
end.
//unit2.dfm
object Form2: TForm2
Left = 192
Top = 106
Width = 378
Height = 237
Caption = 'Form2'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Memo1: TMemo
Left = 8
Top = 8
Width = 353
Height = 193
Lines.Strings = (
'Memo1')
ScrollBars = ssBoth
TabOrder = 0
end
object ServerSocket1: TServerSocket
Active = False
Port = 211
ServerType = stThreadBlocking
OnGetThread = ServerSocket1GetThread
Left = 208
Top = 120
end
end
续
//receive welcome info
j:=0;
while Head<>'220' do
begin
if j<100 then
begin
FillChar(recvbuf,sizeof(recvbuf),0);
if Recv(hSocket,recvbuf,SizeOf(recvbuf),0)=SOCKET_ERROR then
begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Receive Welcome Infomation error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
recvbuf[StrLen(recvbuf)-2]:=#0;
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',RECV:'+recvbuf+'"',Now));
StrLCopy(Head,recvbuf,3);
Inc(j);
end
else
begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Receive Welcome Infomation Head error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
end;
//send "helo" to host
FillChar(sendbuf,sizeof(sendbuf),0);
StrCopy(sendbuf,PChar('HELO '+SmtpHostIp[SmtpId]+#13#10));
if Send(hSocket,sendbuf,StrLen(sendbuf),0)=SOCKET_ERROR then
begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Send HELO error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
sendbuf[StrLen(sendbuf)-2]:=#0;
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',SEND:'+sendbuf+'"',Now));
FillChar(recvbuf,sizeof(recvbuf),0);
if Recv(hSocket,recvbuf,SizeOf(recvbuf),0)=SOCKET_ERROR then
begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Receive HELO Reply error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
recvbuf[StrLen(recvbuf)-2]:=#0;
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',RECV:'+recvbuf+'"',Now));
StrLCopy(Head,recvbuf,3);
if Head<>'250' then
begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Receive HELO Reply Head error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
续
function SEmailThrd(p:Pointer):LongInt;stdcall;
var
MyWSA: WSAData;
SIN: TSockAddr;
hSocket: TSocket;
sendbuf:array[0..1023] of char;
recvbuf:array[0..127] of char;
Head:array[0..3] of char;
j:integer;
RecverName:String;
SmtpId:integer;
PrtStr:String;
LogStr:String;
begin
result:=0;
SmtpId:=TParam(p^).TrdId mod SmtpCount;
if SmtpId=0 then SmtpId:=SmtpCount;
FillChar(Head,sizeof(Head),0);
//initial socket
If WSAStartup(MAKEWORD(2,2), MyWSA) <> 0 Then
Begin
WSACleanup;
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',WSAStartup error"',Now));
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',End Thread"',Now));
Dec(PrcsThrdCount);
Exit;
end;
hSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
If hSocket = INVALID_SOCKET Then
Begin
WSACleanup;
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Create Socket error"',Now));
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',End Thread"',Now));
Dec(PrcsThrdCount);
Exit;
End;
SIN.sin_family := AF_INET;
SIN.sin_port := htons(25);
SIN.sin_addr.S_addr := inet_addr(PChar(SmtpHostIp[SmtpId]));
If connect(hSocket, SIN, SizeOf(SIN)) = SOCKET_ERROR Then
Begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Connect Host error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
if SetSockOpt(hSocket,SOL_SOCKET,SO_RCVTIMEO,PChar(@TimeOut),SizeOf(TimeOut))=SOCKET_ERROR then
begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Set Receive TimeOut error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;
if SetSockOpt(hSocket,SOL_SOCKET,SO_SNDTIMEO,PChar(@TimeOut),SizeOf(TimeOut))=SOCKET_ERROR then
begin
Writeln(LogFile,FormatDateTime('yyyy-mm-dd hh:nn:ss",'+IntToStr(TParam(p^).TrdId)+',Set Send TimeOut error"',Now));
CallExit(hSocket,TParam(p^).TrdId);
Exit;
end;