📄 hxudp.pas
字号:
PeerPort:= ntohs(saRemote.sin_port);
end;
if ret = SOCKET_ERROR then
begin
ErrorCode:= GetLastError;
if ErrorCode <> WSAEWOULDBLOCK then
begin
if Assigned(FOnSocketError) then
FOnSocketError(Self, utRecv, ErrorCode);
if ErrorCode <> 0 then
raise TUDPException.CreateFmt('接收数据出错。错误码是%d', [ErrorCode]);
end;
end
else
Result:= True;
end;
function ThxUDPSocket.SendBuf(var Buf; Size: Integer; IP: string; Port: Integer): Boolean;
var
ret, ErrorCode: Integer;
saRemote: TSockAddrIn;
begin
Result:= False;
saRemote.sin_family:= AF_INET;
saRemote.sin_port:= htons(Port);
saRemote.sin_addr.S_addr:= inet_addr(PChar(IP));
if saRemote.sin_addr.S_addr = INADDR_NONE then
raise TUDPException.Create('无效的远程主机地址!');
if FProxyInfo.Enabled then
ret:= SendByProxy(FSocket, Buf, Size, IP, Port)
else
ret:= sendto(FSocket, Buf, Size, 0, saRemote, SizeOf(saRemote));
if ret = SOCKET_ERROR then
begin
ErrorCode:= GetLastError;
if ErrorCode <> WSAEWOULDBLOCK then
begin
if Assigned(FOnSocketError) then
FOnSocketError(Self, utSend, ErrorCode);
if ErrorCode <> 0 then
raise TUDPException.CreateFmt('发送数据时出错。错误码是%d', [ErrorCode]);
end;
end
else
Result:= True;
end;
function ThxUDPSocket.SendText(Text, IP: string; Port: integer): Boolean;
begin
Result := SendBuf(Pointer(Text)^, Length(Text), IP, Port);
end;
procedure ThxUDPSocket.SetActive(Value: Boolean);
begin
if FActive <> Value then
DoActive(Value);
end;
procedure ThxUDPSocket.SetRecvBufSize(Value: Integer);
var
ErrorCode: Integer;
begin
if FRecvBufSize <> Value then
begin
ErrorCode:= setsockopt(FSocket, SOL_SOCKET, SO_RCVBUF, @Value, sizeof(Value));
if ErrorCode = SOCKET_ERROR then
raise TUDPException.CreateFmt('设置接收缓冲区出错。错误码是%d', [GetLastError]);
FRecvBufSize:= Value;
end;
end;
procedure ThxUDPSocket.SetSendBufSize(Value: Integer);
var
ErrorCode: Integer;
begin
if FSendBufSize <> Value then
begin
ErrorCode:= setsockopt(FSocket, SOL_SOCKET, SO_SNDBUF, @Value, sizeof(Value));
if ErrorCode = SOCKET_ERROR then
raise TUDPException.CreateFmt('设置发送缓冲区错误。错误码是%d', [GetLastError]);
FSendBufSize:= Value;
end;
end;
procedure ThxUDPSocket.SetTimeOut(Value: Longword);
begin
if FTimeOut <> Value then
FTimeOut:= Value;
end;
function ThxUDPSocket.ConnectToProxy: Boolean;
var
saProxy: TSockAddrIn;
ret: Integer;
bRet: Boolean;
begin
Result:= False;
//建立到Proxy的Tcp连接
if FTcpSocket = INVALID_SOCKET then
FTcpSocket:= socket(AF_INET, SOCK_STREAM, 0);
saProxy.sin_family:= AF_INET;
saProxy.sin_port:= htons(FProxyInfo.Port);
saProxy.sin_addr.S_addr:= inet_addr(PChar(FProxyInfo.Address));
ret:= connect(FTcpSocket, @saProxy, SizeOf(saProxy));
if ret = SOCKET_ERROR then
raise Exception.CreateFmt('无法连接到代理服务器,错误码是%d', [WSAGetLastError]);
{代理服务器是否需要身份验证}
if Trim(FProxyInfo.Username) <> '' then
bRet:= Handclasp(FTcpSocket, atUserPass)
else
bRet:= Handclasp(FTcpSocket, atNone);
if not bRet then
begin
closesocket(FTcpSocket);
raise Exception.CreateFmt('代理服务器身份验证失败!错误码是%d', [WSAGetLastError]);
end;
//建立UDP映射通道
if not MapUdpChannel(FTcpSocket) then
begin
closesocket(FTcpSocket);
raise Exception.CreateFmt('代理服务器不支持UDP!错误码是%d', [WSAGetLastError]);
end;
Result:= True;
end;
function ThxUDPSocket.Handclasp(Socket: TSocket; AuthenType: TAuthenType): Boolean;
var
Buf: array[0..255] of Byte;
I, Ret: Integer;
Username, Password: string;
begin
Result:= False;
case AuthenType of
// 无需验证
atNone:
begin
Buf[0]:= $05;
Buf[1]:= $01;
Buf[2]:= $00;
Ret:= send(Socket, Buf, 3, 0);
if Ret = -1 then Exit;
FillChar(Buf, 256, #0);
Ret:= recv(Socket, Buf, 256, 0);
if Ret < 2 then Exit;
if Buf[1] <> $00 then Exit;
Result:= True;
end;
// 用户名密码验证
atUserPass:
begin
Buf[0]:= $05; // Socks版本号
Buf[1]:= $02; // 两种认证方法
Buf[2]:= $00; // 无需校验
Buf[3]:= $02; // 需用户名密码校验
Ret:= send(Socket, Buf, 4, 0);
if Ret = -1 then Exit;
FillChar(Buf, 256, #0);
Ret:= recv(Socket, Buf, 256, 0);
if Ret < 2 then Exit;
if Buf[1] <> $02 then Exit;
Username:= FProxyInfo.Username;
Password:= FProxyInfo.Password;
FillChar(Buf, 256, #0);
Buf[0]:= $01;
Buf[1]:= Length(Username);
for I:= 0 to Buf[1] - 1 do
Buf[2 + I]:= Ord(Username[I + 1]);
Buf[2 + Length(Username)]:= Length(Password);
for I:= 0 to Buf[2 + Length(Username)] - 1 do
Buf[3 + Length(Username) + I]:= Ord(Password[I + 1]);
Ret:= send(Socket, Buf, Length(Username) + Length(Password) + 3, 0);
if Ret = -1 then Exit;
Ret:= recv(Socket, Buf, 256, 0);
if Ret = -1 then Exit;
if Buf[1] <> $00 then Exit;
Result:= True;
end;
end;
end;
function ThxUDPSocket.MapUdpChannel(Socket: TSocket): Boolean;
var
saLocal: TSockAddrIn;
NameLen: Integer;
ProxyAddr: TInAddr;
ProxyPort: Word;
Buf: array[0..255] of Byte;
begin
Result:= False;
NameLen:= SizeOf(saLocal);
getsockname(FSocket, saLocal, NameLen);
Buf[0]:= $05; //协议版本Socks5
Buf[1]:= $03; //Socks命令:UDP
Buf[2]:= $00; //保留
Buf[3]:= $01; //地址类型IPv4
CopyMemory(@Buf[4], @saLocal.sin_addr, 4);
CopyMemory(@Buf[8], @saLocal.sin_port, 2);
send(Socket, Buf, 10, 0);
FillChar(Buf, 256, #0);
recv(Socket, Buf, 256, 0);
if (Buf[0] <> $05) and (Buf[1] <> $00) then
Exit;
CopyMemory(@ProxyAddr, @Buf[4], 4); //获取Proxy的映射地址
CopyMemory(@ProxyPort, @Buf[8], 2); //获取Proxy的映射端口号
FUdpProxyAddr.sin_family:= AF_INET;
FUdpProxyAddr.sin_port:= ProxyPort;
FUdpProxyAddr.sin_addr:= ProxyAddr;
Result:= True;
end;
function ThxUDPSocket.SendByProxy(Socket: TSocket; var buf; len: Integer;
RemoteIP: string; RemotePort: Integer): Integer;
var
TempBuf: array[0..1023] of Byte;
saRemote: TSockAddrIn;
begin
saRemote.sin_family:= AF_INET;
saRemote.sin_port:= htons(RemotePort);
saRemote.sin_addr.S_addr:= inet_addr(PChar(RemoteIP));
// 加上报头
FillChar(TempBuf, 1023, $0);
TempBuf[0]:= $00; //保留
TempBuf[1]:= $00; //保留
TempBuf[2]:= $00; //是否分段重组(此处不用)
TempBuf[3]:= $01; //IPv4
CopyMemory(@TempBuf[4], @saRemote.sin_addr, 4); //代理服务器地址
CopyMemory(@TempBuf[8], @saRemote.sin_port, 2); //代理服务器端口
CopyMemory(@TempBuf[10], @buf, len); //实际数据
Result:= sendto(Socket, TempBuf, len + 10, 0, FUdpProxyAddr, SizeOf(FUdpProxyAddr));
if Result = SOCKET_ERROR then
raise Exception.CreateFmt('发送数据错误!错误号是%d', [WSAGetLastError]);
end;
function ThxUDPSocket.RecvByProxy(Socket: TSocket; var buf; len: Integer;
RemoteIP: string; RemotePort: Integer): Integer;
var
TempBuf: array[0..1023] of Byte;
saRemote: TSockAddrIn;
fromlen: Integer;
begin
FillChar(TempBuf, 1024, #0);
saRemote.sin_family:= AF_INET;
saRemote.sin_port:= htons(RemotePort);
saRemote.sin_addr.S_addr:= inet_addr(PChar(RemoteIP));
fromlen:= SizeOf(saRemote);
Result:= recvfrom(Socket, TempBuf, len, 0, saRemote, fromlen);
if Result = SOCKET_ERROR then
raise Exception.CreateFmt('接收数据错误!错误号是%d', [WSAGetLastError]);
Assert(TempBuf[0] = $00); //保留
Assert(TempBuf[1] = $00); //保留
Assert(TempBuf[2] = $00); //是否分段重组
Assert(TempBuf[3] = $01); //IPv4
CopyMemory(@saRemote.sin_addr, @TempBuf[4], 4); //代理服务器地址
CopyMemory(@saRemote.sin_port, @TempBuf[8], 2); //代理服务器端口
CopyMemory(@buf, @TempBuf[10], len); //实际数据
end;
{ ThxUdpRecvThread }
constructor ThxUdpRecvThread.Create(CreateSuspended: Boolean; AUdpSocket: ThxUdpSocket);
begin
inherited Create(CreateSuspended);
FSocket:= AUDPSocket;
FEvent:= WSA_INVALID_EVENT;
InitEvent;
end;
destructor ThxUdpRecvThread.Destroy;
begin
if not Terminated then
Stop;
FreeEvent;
inherited Destroy;
end;
procedure ThxUdpRecvThread.Execute;
var
ErrorCode: Integer;
begin
while not Terminated do
begin
ErrorCode:= WSAWaitForMultipleEvents(
1, //事件数量
@FEvent,//事件处理函数
False, //有一个事件触发时就返回
FSocket.FTimeOut, // 超时时间
False //函数返回时,不执行I/O例程
);
if Terminated then
Break;
if ErrorCode = WAIT_IO_COMPLETION then
begin
Break;
end
else
begin
WSAResetEvent(FEvent);
if ErrorCode = WSA_WAIT_TIMEOUT then
begin
if Assigned(FSocket.FOnTimeOut) then
Synchronize(FSocket.FOnTimeOut);
end
else if Assigned(FOnDataRecv) then
Synchronize(FOnDataRecv);
end;
end;
end;
procedure ThxUdpRecvThread.FreeEvent;
begin
if FEvent <> WSA_INVALID_EVENT then
WSACloseEvent(FEvent);
end;
procedure ThxUdpRecvThread.InitEvent;
var
ErrorCode: Integer;
begin
FEvent:= WSACreateEvent;
if FEvent = WSA_INVALID_EVENT then
raise TUDPException.CreateFmt('创建套接字事件句柄出错。错误码是%d', [WSAGetLastError]);
ErrorCode:= WSAEventSelect(FSocket.FSocket, FEvent, FD_READ);
if ErrorCode = SOCKET_ERROR then
raise TUDPException.CreateFmt('设置套接字事件句柄出错。错误码是%d', [WSAGetLastError]);
end;
procedure ThxUdpRecvThread.Stop;
begin
Terminate;
SetEvent(FEvent);
WaitFor;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -