forked from winddriver/Delphi-Cross-Socket
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNet.RawSocket.pas
189 lines (155 loc) · 5.03 KB
/
Net.RawSocket.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
unit Net.RawSocket;
interface
uses
System.SysUtils, Net.SocketAPI,
{$IFDEF POSIX}
Posix.Base, Posix.SysSocket, Posix.NetinetIn
{$ELSE}
Winapi.Windows, Net.Winsock2, Net.Wship6
{$ENDIF};
type
/// <summary>
/// 简单的套接字操作类
/// </summary>
TRawSocket = class
private
FSocket: THandle;
FSockAddr: TRawSockAddrIn;
FPeerAddr: string;
FPeerPort: Word;
public
/// <summary>
/// 关闭 Socket
/// </summary>
procedure Close;
/// <summary>
/// 连接到主机, 支持 IPv6
/// </summary>
function Connect(const AHost: string; APort: Word): Integer;
/// <summary>
/// 绑定 Socket 到指定地址和端口, 支持 IPv6
/// </summary>
function Bind(const Addr: string; APort: Word): Integer;
/// <summary>
/// 启动监听
/// </summary>
function Listen(backlog: Integer = SOMAXCONN): Integer;
/// <summary>
/// 接受一个连接请求, 并分配 Socket
/// </summary>
function Accept(Addr: PSockAddr; AddrLen: PInteger): THandle;
/// <summary>
/// 接收数据
/// </summary>
function Recv(var Buf; len: Integer; flags: Integer = 0): Integer;
/// <summary>
/// 发送数据
/// </summary>
function Send(const Buf; len: Integer; flags: Integer = 0): Integer;
/// <summary>
/// 接收数据从指定地址端口(用于UDP)
/// </summary>
function RecvFrom(const Addr: PSockAddr; var AddrLen: Integer; var Buf;
len: Integer; flags: Integer = 0): Integer;
/// <summary>
/// 发送数据到指定地址端口(用于UDP)
/// </summary>
function SendTo(const Addr: PSockAddr; AddrLen: Integer; const Buf;
len: Integer; flags: Integer = 0): Integer;
/// <summary>
/// 判断套接字是否有效
/// </summary>
function IsValid: Boolean;
/// <summary>
/// 套接字句柄
/// </summary>
property Socket: THandle read FSocket;
/// <summary>
/// 套接字地址信息
/// 如果是 Connect 到远端的套接字, 则该地址保存的是远端地址信息
/// 如果是 Bind 到本地的套接字, 则该地址保存的是本地地址信息
/// </summary>
property SockAddr: TRawSockAddrIn read FSockAddr;
property PeerAddr: string read FPeerAddr;
property PeerPort: Word read FPeerPort;
end;
implementation
{ TRawSocket }
procedure TRawSocket.Close;
begin
if (FSocket = INVALID_HANDLE_VALUE) then Exit;
TSocketAPI.CloseSocket(FSocket);
FSocket := INVALID_HANDLE_VALUE;
end;
function TRawSocket.Connect(const AHost: string; APort: Word): Integer;
var
LHints: TRawAddrInfo;
LAddrInfo: PRawAddrInfo;
begin
FillChar(LHints, SizeOf(TRawAddrInfo), 0);
LHints.ai_family := AF_UNSPEC;
LHints.ai_socktype := SOCK_STREAM;
LHints.ai_protocol := IPPROTO_TCP;
LAddrInfo := TSocketAPI.GetAddrInfo(AHost, APort.ToString, LHints);
if (LAddrInfo = nil) then Exit(-1);
try
FSocket := TSocketAPI.NewSocket(LAddrInfo.ai_family, LAddrInfo.ai_socktype,
LAddrInfo.ai_protocol);
if (FSocket = INVALID_HANDLE_VALUE) then Exit(-1);
FSockAddr.AddrLen := LAddrInfo.ai_addrlen;
Move(LAddrInfo.ai_addr^, FSockAddr.Addr, LAddrInfo.ai_addrlen);
TSocketAPI.ExtractAddrInfo(@FSockAddr.Addr, FSockAddr.AddrLen, FPeerAddr, FPeerPort);
TSocketAPI.SetKeepAlive(FSocket, 5, 3, 5);
Result := TSocketAPI.Connect(FSocket, @FSockAddr.Addr, FSockAddr.AddrLen);
finally
TSocketAPI.FreeAddrInfo(LAddrInfo);
end;
end;
function TRawSocket.Bind(const Addr: string; APort: Word): Integer;
var
LHints: TRawAddrInfo;
LAddrInfo: PRawAddrInfo;
begin
FillChar(LHints, SizeOf(TRawAddrInfo), 0);
LHints.ai_family := AF_UNSPEC;
LHints.ai_socktype := SOCK_STREAM;
LHints.ai_protocol := IPPROTO_TCP;
LAddrInfo := TSocketAPI.GetAddrInfo(Addr, APort.ToString, LHints);
if (LAddrInfo = nil) then Exit(-1);
FSockAddr.AddrLen := LAddrInfo.ai_addrlen;
Move(LAddrInfo.ai_addr^, FSockAddr.Addr, LAddrInfo.ai_addrlen);
TSocketAPI.FreeAddrInfo(LAddrInfo);
TSocketAPI.ExtractAddrInfo(@FSockAddr.Addr, FSockAddr.AddrLen, FPeerAddr, FPeerPort);
Result := TSocketAPI.Bind(FSocket, @FSockAddr.Addr, FSockAddr.AddrLen);
end;
function TRawSocket.Listen(backlog: Integer): Integer;
begin
Result := TSocketAPI.Listen(FSocket, backlog);
end;
function TRawSocket.Accept(Addr: PSockAddr; AddrLen: PInteger): THandle;
begin
Result := TSocketAPI.Accept(FSocket, Addr, AddrLen);
end;
function TRawSocket.Recv(var Buf; len, flags: Integer): Integer;
begin
Result := TSocketAPI.Recv(FSocket, Buf, len, flags);
end;
function TRawSocket.Send(const Buf; len, flags: Integer): Integer;
begin
Result := TSocketAPI.Send(FSocket, Buf, len, flags);
end;
function TRawSocket.RecvFrom(const Addr: PSockAddr; var AddrLen: Integer;
var Buf; len, flags: Integer): Integer;
begin
Result := TSocketAPI.RecvFrom(FSocket, Addr, AddrLen, Buf, len, flags);
end;
function TRawSocket.SendTo(const Addr: PSockAddr; AddrLen: Integer; const Buf;
len: Integer; flags: Integer): Integer;
begin
Result := TSocketAPI.SendTo(FSocket, Addr, AddrLen, Buf, len, flags);
end;
function TRawSocket.IsValid: Boolean;
begin
Result := TSocketAPI.IsValidSocket(FSocket);
end;
end.