📄 mudt.pas
字号:
Unit mudt;
Interface
{$INCLUDE mcompile.inc}
Uses
SysUtils, Classes, udt,
{$ifdef KYLIX}
Libc,
{$else}
Windows, Winsock, JwaWinsock2, JwaWS2tcpip,
{$ENDIF}
StrUtils, SyncObjs;
Const
DEFAULT_PORT = '6000';
DEFAULT_BUF_LEN = 1048576;
Type
TMUDT = Class;
TMUDTListenThread = Class(TThread)
Public
Host: TMUDT;
Procedure Execute; Override;
End;
TMUDTRecvThread = Class(TThread)
Public
PeerIP: String;
PeerPort: String;
Data: pChar;
Host: TMUDT;
socket: UDTSOCKET;
Procedure Execute; Override;
End;
TMUDTOnDataReceived = Procedure (Thread: TMUDTRecvThread; Data: pChar; len: Integer) Of Object;
TMUDT = Class(TComponent)
Private
CS: TCriticalSection;
FPort: String;
FPeerIP: String;
FPeerPort: String;
FLastError: String;
FBindLocalPort: Boolean;
FConnected: Boolean;
socket: UDTSOCKET;
servThread: TMUDTListenThread;
FOnDataReceived: TMUDTOnDataReceived;
FOnSocketLost: TNotifyEvent;
Public
Property Port: String Read FPort Write FPort;
Property PeerIP: String Read FPeerIP Write FPeerIP;
Property PeerPort: String Read FPeerPort Write FPeerPort;
Property LastError: String Read FLastError;
Property BindLocalPort: Boolean Read FBindLocalPort Write FBindLocalPort;
Property Connected: Boolean Read FConnected;
Property OnDataReceived: TMUDTOnDataReceived Read FOnDataReceived Write FOnDataReceived;
Property OnSocketLost: TNotifyEvent Read FOnSocketLost Write FOnSocketLost;
Constructor Create(AOwner: TComponent); Override;
Destructor Destroy; Override;
Procedure Connect;
Function Send(data: pChar; len: Integer): Boolean;
Procedure Close;
Function Listen: Boolean;
End;
Procedure Register;
Implementation
Procedure Register;
Begin
RegisterComponents('Kirikawa Kits', [TMUDT]);
End;
Constructor TMUDT.Create(AOwner: TComponent);
Begin
Inherited;
CS := TCriticalSection.Create;
FPort := DEFAULT_PORT;
socket := INVALID_SOCK;
FBindLocalPort := False;
FConnected := False;
End;
Destructor TMUDT.Destroy;
Begin
CS.Free;
Inherited;
End;
Procedure TMUDT.Connect;
Var
hints: addrinfo;
local, peer: pAddrInfo;
size: Integer;
Begin
FillChar(hints, sizeof(addrinfo), #0);
hints.ai_flags := AI_PASSIVE;
hints.ai_family := AF_INET;
hints.ai_socktype := Integer(SOCK_DGRAM);
If GetAddrInfo(Nil, pChar(FPort), @hints, local) <> 0 Then
Begin
FLastError := 'Incorrect network address.';
Exit;
End;
socket := UDT.socket(local^.ai_family, local^.ai_socktype, local^.ai_protocol);
{$ifdef DELPHI}
size := 1052;
UDT.setsockopt(socket, 0, UDT_MSS, @size, 4);
{$endif}
If FBindLocalPort Then
If UDT.bind(socket, local^.ai_addr, local^.ai_addrlen) = UDT.ERROR Then
Begin
FLastError := 'Bind failed: ' + StrPas(udt.getlasterror);
FreeAddrInfo(local);
Exit;
End;
FreeAddrInfo(local);
If GetAddrInfo(pChar(FPeerIP), pChar(FPeerPort), @hints, peer) <> 0 Then
Begin
FLastError := 'Incorrect server/peer address: ' + FPeerIP + '/' + FPeerPort;
Exit;
End;
If UDT.connect(socket, peer^.ai_addr, peer^.ai_addrlen) = UDT.ERROR Then
Begin
FLastError := 'Connect: ' + StrPas(UDT.getlasterror);
FreeAddrInfo(peer);
Exit;
End;
FreeAddrInfo(peer);
FConnected := True;
End;
Function TMUDT.Send(data: pChar; len: Integer): Boolean;
Var
i: Integer;
Begin
Result := False;
If Not FConnected Then
Begin
FLastError := 'Socket not connected yet.';
Exit;
End;
i := UDT.sendmsg(socket, data, len, -1, true);
If i = UDT.ERROR Then
Begin
FLastError := 'Send: ' + StrPas(udt.GetLastError);
Close;
Exit;
End;
Result := True;
End;
Procedure TMUDT.Close;
Begin
FConnected := False;
If socket <> INVALID_SOCK Then UDT.close(socket);
socket := INVALID_SOCK;
End;
Function TMUDT.Listen: Boolean;
Var
hints: AddrInfo;
res: pAddrInfo;
Begin
Result := True;
If FConnected Then
Begin
FLastError := 'Already connected. Close first or create a new one.';
Exit;
End;
FillChar(hints, SizeOf(AddrInfo), 0);
hints.ai_flags := AI_PASSIVE;
hints.ai_family := AF_INET;
//hints.ai_socktype := Integer(SOCK_STREAM);
hints.ai_socktype := Integer(SOCK_DGRAM);
If GetAddrInfo(Nil, pChar(FPort), @hints, res) <> 0 Then
Begin
FLastError := 'Illegal port number or port is busy.';
Exit;
End;
socket := UDT.socket(res.ai_family, res.ai_socktype, res.ai_protocol);
// UDT Options
//UDT::setsockopt(serv, 0, UDT_CC, new CCCFactory<CUDPBlast>, sizeof(CCCFactory<CUDPBlast>));
//UDT::setsockopt(serv, 0, UDT_MSS, new int(9000), sizeof(int));
//UDT::setsockopt(serv, 0, UDT_RCVBUF, new int(10000000), sizeof(int));
//UDT::setsockopt(serv, 0, UDP_RCVBUF, new int(10000000), sizeof(int));
If UDT.bind(socket, res.ai_addr, res.ai_addrlen) = UDT.ERROR Then
Begin
FLastError := 'bind: ' + UDT.GetLastError;
FreeAddrInfo(res);
Exit;
End;
FreeAddrInfo(res);
If UDT.listen(socket, 10) = UDT.ERROR Then
Begin
FLastError := 'listen: ' + UDT.getlasterror;
Exit;
End;
FConnected := True;
servThread := TMUDTListenThread.Create(True);
servThread.FreeOnTerminate := True;
servThread.Host := self;
servThread.Resume;
Result := True;
End;
{* TMUDTListenThread *}
Procedure TMUDTListenThread.Execute;
Var
clientaddr: sockaddr_storage;
recver: UDTSOCKET;
Addrlen: Integer;
dSockAddr: SockAddr;
clienthost: Array [0..NI_MAXHOST - 1] Of Char;
clientservice: Array [0..NI_MAXSERV - 1] Of Char;
socket: Integer;
client: TMUDTRecvThread;
Begin
Addrlen := SizeOf(clientaddr);
socket := Host.socket;
While Not Terminated Do
Begin
Move(clientaddr, dSockAddr, SizeOf(dSockAddr));
recver := UDT.accept(socket, @dSockAddr, @addrlen);
If recver = UDT.INVALID_SOCK Then
Begin
Host.FLastError := StrPas(UDT.GetLastError);
Host.FConnected := False;
Break;
End;
{$IFDEF DELPHI}
GetNameinfo(@dSockAddr, addrlen, clienthost, sizeof(clienthost), clientservice, sizeof(clientservice), NI_NUMERICHOST Or NI_NUMERICSERV);
{$ENDIF}
{$IFDEF KYLIX}
GetNameinfo(dSockAddr, addrlen, clienthost, sizeof(clienthost), clientservice, sizeof(clientservice), NI_NUMERICHOST Or NI_NUMERICSERV);
{$ENDIF}
client := TMUDTRecvThread.Create(True);
client.FreeOnTerminate := True;
client.socket := recver;
client.PeerPort := ClientService;
client.PeerIP := ClientHost;
client.Host := Host;
client.Resume;
End;
udt.close(socket);
If Assigned(Host.FOnSocketLost) Then Host.FOnSocketLost(Host);
End;
{* TMUDTRecvThread *}
Procedure TMUDTRecvThread.Execute;
Var
data: pChar;
size: Integer;
rs: Integer;
Begin
size := DEFAULT_BUF_LEN;
data := AllocMem(size);
While Not Terminated Do
Begin
rs := UDT.recvmsg(socket, data, size);
If rs = UDT.ERROR Then
Begin
Break;
End;
If rs > 0 Then
If Assigned(Host.FOnDataReceived) Then
Host.FOnDataReceived(self, data, rs);
End;
FreeMem(data, size);
UDT.close(socket);
End;
End.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -