如何在Internet上使用UDP广播方式呢?(300分)

  • 主题发起人 主题发起人
  • 开始时间 开始时间
你找到 我说的那本书,上面有详细的资料和代码的
 
:)哦,还有要路由器支持。
 
那么,在中国的网络上用多播技术是行不通的哦?
还需要硬件的支持,而且这些硬件还不能由我们左右的。
 
多播也只是针对居域网的。。
 
Internet 所有的邮件系统都是采用Udp广播的形式发送的,只不过在广播的包头中包含
目标地址的IP号和端口号,是你的地址才能接收,开包,解密.否则丢弃.
 
to china_delphi:
"广播的包头中包含目标地址的IP号和端口号"这是如何实现的?在WIN2K的系统上,好像不能
修改数据包的。
 
用WINSOCK函数, 函数修改这个头,系统用IGMP包通知路由器。就OK了,具体的
找相关资料
 
如果你仔细用一些嗅探工具的话,你就会发现QQ对每一个在线用户有的时候发送
ICMP包,尤其是在经常要服务器中转消息的时候,类型为3,代码有的时候为7,
具体的有可能有变化。
 
for 枫,在WIN2K下可以修改数据包的,我做过自定义UDP/ICMP包的IP头程序,
调试通过.............
 
to 张无忌
可否借“自定义UDP/ICMP包的IP头程序”例程一观?感谢
 
pls mailto:pjntt@21cn.com
 
这是别人写的,我看了一下,大致是对的,我的代码在家里,过几天再联系把
  IP地址的隐藏
一、前言

  本文主要介绍如何在程序中实现IP地址的隐藏。其实这篇东西不算我写的。其中《IP头结构》部分我懒得打字,故复制、粘贴了孤独剑客的文章,先说声谢谢!代码部分参考了外国程序xes写的一个程序。所以这只是学习过程中的一个副产品。既然程序已经做好了,就顺便放上来跟大家一起交流,共同提高吧。本文只不过想说明一下IP数据的结构和发送机制。如果有人把它改为恶意IP攻击工具,后果自负。

二、IP头结构

我们知道,TCP/IP网络数据全部是通过封装在IP数据包中在Internet网上传送的,也就是封装建立起一个包含IP头和数据的IP数据报。一般来说,网络软件总是以多个32位字产生IP头,即使必须用附加的0填充IP头。IP头包含了传输IP数据包中封装数据的所有必要信息。IP头的数据结构和描述如下:

成员 长度(Bit) 描述
Version 4 IP头的版本号,目前是IPv4,最新是IPv6
Header Length 4 IP头的长度,若没有特殊选择,IP头总是20字节长
Type of Service 8 服务类型,定义了数据传输的优先级、延迟、吞吐量和可靠性等特性
Total Packet Length 16 IP包的长度,若没有特殊选项,一般为20字节长
Identification 16 IP包标识,主机使用它唯一确定每个发送的数据报
Flag 3 IP数据分割标志
Fragment Offset 13 IP数据分割偏移
Time to Live 8 数据报在网络上的存活时间,每通过一个路由器,该数值减一
Protocol 8 TCP/IP协议类型,比如:ICMP为1,IGMP为2,TCP为6,UDP为17等
Header Checksum 16 头部检验和
Source IP Address 32 源IP地址
Destination IP Address 32 目的IP地址
Other ? 其他选项
Data ? 数据

实现自己定义的IP头是一件非常有意义的事情,比如,通过改变IP头里的TOS的优先级和TTL,你可以使自己的数据包有更强的传输能力和寿命,通过修改IP头里的源IP地址就可以隐藏自己机器的IP地址等等。象著名攻击程序“泪滴TearDrop”就是通过故意制造系统不能处理的分片IP包而实现的,还有SYN Flooder和UDP Flooder就是通过产生随机源IP实现欺骗的。

三、实现原理

一般来说,自定义IP头是通过使用socket的库函数setsockopt()的选项IP_HDRINCL来实现的,尽管这在unix和linux平台上很容易实现,但遗憾的是在Windows平台的Winsock1.1和Winsock2.0函数库里setsockopt()不支持IP_HDRINCL选项,所以在Windows 9x/NT里是无法通过Winsock函数库来实现IP头自定义的,当然可以通过编写虚拟设备驱动程序来实现,不过比较复杂,但Windows 2000的出现打破了这种局面,Windows2000的Winsock2.2函数库里全面支持setsockopt()的选项IP_HDRINCL,使得我们轻松就可以实现自定义的IP头。实现方法如下:

四、代码部分

{

1. 本程序只能运行于 Window 2000.

2. 你必须有 Administrator 权限.

3. 程序需要用到一个 button 和一个 memo.
----------------------------------------------------------------------
运行程序前,请根据自己的需要改变 SrcIP、SrcPort、DestIP和DestPort的值
----------------------------------------------------------------------
如果你看不懂以下代码,最好不要去运行它。
----------------------------------------------------------------------
}

unit Unit1;
interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, OleCtrls, Registry;

Const
SrcIP = '123.123.123.1';//发送方IP地址
SrcPort = 1234; //发送方端口
DestIP = '127.0.0.2'; //目的IP地址
DestPort = 4321; //目的端口

Max_Message = 4068;
Max_Packet = 4096;

type

TPacketBuffer = Array[0..Max_Packet-1] of byte;

TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure SendIt;
end;

// IP 头
type
T_IP_Header = record
ip_verlen : Byte;
ip_tos : Byte;
ip_totallength : Word;
ip_id : Word;
ip_offset : Word;
ip_ttl : Byte;
ip_protocol : Byte;
ip_checksum : Word;
ip_srcaddr : LongWord;
ip_destaddr : LongWord;
end;

// UDP 头
Type
T_UDP_Header = record
src_portno : Word;
dst_portno : Word;
udp_length : Word;
udp_checksum : Word;
end;

// 一些 Winsock 2 的类型声明
u_char = Char;
u_short = Word;
u_int = Integer;
u_long = Longint;

SunB = packed record
s_b1, s_b2, s_b3, s_b4: u_char;
end;
SunW = packed record
s_w1, s_w2: u_short;
end;
in_addr = record
case integer of
0: (S_un_b: SunB);
1: (S_un_w: SunW);
2: (S_addr: u_long);
end;
TInAddr = in_addr;
Sockaddr_in = record
case Integer of
0: (sin_family: u_short;
sin_port: u_short;
sin_addr: TInAddr;
sin_zero: array[0..7] of Char);
1: (sa_family: u_short;
sa_data: array[0..13] of Char)
end;
TSockAddr = Sockaddr_in;
TSocket = u_int;

const
WSADESCRIPTION_LEN = 256;
WSASYS_STATUS_LEN = 128;

type
PWSAData = ^TWSAData;
WSAData = record // WSDATA
wVersion: Word;
wHighVersion: Word;
szDescription: array[0..WSADESCRIPTION_LEN] of Char;
szSystemStatus: array[0..WSASYS_STATUS_LEN] of Char;
iMaxSockets: Word;
iMaxUdpDg: Word;
lpVendorInfo: PChar;
end;
TWSAData = WSAData;

//定义一些 winsock 2 函数
function closesocket(s: TSocket): Integer; stdcall;
function socket(af, Struct, protocol: Integer): TSocket; stdcall;
function sendto(s: TSocket; var Buf; len, flags: Integer; var addrto: TSockAddr;
tolen: Integer): Integer; stdcall;{}
function setsockopt(s: TSocket; level, optname: Integer; optval: PChar;
optlen: Integer): Integer; stdcall;
function inet_addr(cp: PChar): u_long; stdcall; {PInAddr;} { TInAddr }
function htons(hostshort: u_short): u_short; stdcall;
function WSAGetLastError: Integer; stdcall;
function WSAStartup(wVersionRequired: word; var WSData: TWSAData): Integer; stdcall;
function WSACleanup: Integer; stdcall;

const
AF_INET = 2; // internetwork: UDP, TCP, etc.

IP_HDRINCL = 2; // IP Header Include

SOCK_RAW = 3; // raw-protocol interface

IPPROTO_IP = 0; // dummy for IP
IPPROTO_TCP = 6; // tcp
IPPROTO_UDP = 17; // user datagram protocol
IPPROTO_RAW = 255; // raw IP packet

INVALID_SOCKET = TSocket(NOT(0));
SOCKET_ERROR = -1;

var
Form1: TForm1;

implementation

// Import Winsock 2 functions
const WinSocket = 'WS2_32.DLL';

function closesocket; external winsocket name 'closesocket';
function socket; external winsocket name 'socket';
function sendto; external winsocket name 'sendto';
function setsockopt; external winsocket name 'setsockopt';
function inet_addr; external winsocket name 'inet_addr';
function htons; external winsocket name 'htons';
function WSAGetLastError; external winsocket name 'WSAGetLastError';
function WSAStartup; external winsocket name 'WSAStartup';
function WSACleanup; external winsocket name 'WSACleanup';


{$R *.DFM}

function CheckSum(Var Buffer; Size : integer) : Word;
type
TWordArray = Array[0..1] of Word;
var
ChkSum : LongWord;
i : Integer;
begin
ChkSum := 0;
i := 0;
While Size > 1 do begin
ChkSum := ChkSum + TWordArray(Buffer);
inc(i);
Size := Size - SizeOf(Word);
end;

if Size=1 then ChkSum := ChkSum + Byte(TWordArray(Buffer));

ChkSum := (ChkSum shr 16) + (ChkSum and $FFFF);
ChkSum := ChkSum + (Chksum shr 16);

Result := Word(ChkSum);
end;


procedure BuildHeaders(
FromIP : String;
iFromPort : Word;
ToIP : String;
iToPort : Word;
StrMessage : String;
Var Buf : TPacketBuffer;
Var remote : TSockAddr;
Var iTotalSize : Word
);
Var
dwFromIP : LongWord;
dwToIP : LongWord;

iIPVersion : Word;
iIPSize : Word;
ipHdr : T_IP_Header;
udpHdr : T_UDP_Header;

iUdpSize : Word;
iUdpChecksumSize : Word;
cksum : Word;

Ptr : ^Byte;

procedure IncPtr(Value : Integer);
begin
ptr := pointer(integer(ptr) + Value);
end;

begin
// Convert ip address'ss

dwFromIP := inet_Addr(PChar(FromIP));
dwToIP := inet_Addr(PChar(ToIP));

// 初始化 IP 头
//
iTotalSize := sizeof(ipHdr) + sizeof(udpHdr) + length(strMessage);

iIPVersion := 4;
iIPSize := sizeof(ipHdr) div sizeof(LongWord);

ipHdr.ip_verlen := (iIPVersion shl 4) or iIPSize;
ipHdr.ip_tos := 0; // IP type of service
ipHdr.ip_totallength := htons(iTotalSize); // Total packet len
ipHdr.ip_id := 0; // Unique identifier: set to 0
ipHdr.ip_offset := 0; // Fragment offset field
ipHdr.ip_ttl := 128; // Time to live
ipHdr.ip_protocol := $11; // Protocol(UDP)
ipHdr.ip_checksum := 0 ; // IP checksum
ipHdr.ip_srcaddr := dwFromIP; // Source address
ipHdr.ip_destaddr := dwToIP; // Destination address
//
// 初始化 UDP 头
//
iUdpSize := sizeof(udpHdr) + length(strMessage);

udpHdr.src_portno := htons(iFromPort) ;
udpHdr.dst_portno := htons(iToPort) ;
udpHdr.udp_length := htons(iUdpSize) ;
udpHdr.udp_checksum := 0 ;

iUdpChecksumSize := 0;

ptr := @buf[0];
FillChar(Buf, SizeOf(Buf), 0);

Move(ipHdr.ip_srcaddr, ptr^, SizeOf(ipHdr.ip_srcaddr));
IncPtr(SizeOf(ipHdr.ip_srcaddr));

iUdpChecksumSize := iUdpChecksumSize + sizeof(ipHdr.ip_srcaddr);

Move(ipHdr.ip_destaddr, ptr^, SizeOf(ipHdr.ip_destaddr));
IncPtr(SizeOf(ipHdr.ip_destaddr));

iUdpChecksumSize := iUdpChecksumSize + sizeof(ipHdr.ip_destaddr);

IncPtr(1);

Inc(iUdpChecksumSize);

Move(ipHdr.ip_protocol, ptr^, sizeof(ipHdr.ip_protocol));
IncPtr(sizeof(ipHdr.ip_protocol));
iUdpChecksumSize := iUdpChecksumSize + sizeof(ipHdr.ip_protocol);

Move(udpHdr.udp_length, ptr^, sizeof(udpHdr.udp_length));
IncPtr(sizeof(udpHdr.udp_length));
iUdpChecksumSize := iUdpChecksumSize + sizeof(udpHdr.udp_length);

move(udpHdr, ptr^, sizeof(udpHdr));
IncPtr(sizeof(udpHdr));
iUdpChecksumSize := iUdpCheckSumSize + sizeof(udpHdr);

Move(StrMessage[1], ptr^, Length(strMessage));
IncPtr(Length(StrMessage));

iUdpChecksumSize := iUdpChecksumSize + length(strMessage);

cksum := checksum(buf, iUdpChecksumSize);
udpHdr.udp_checksum := cksum;

//
// 现在 IP 和 UDP 头OK了,我们可以把它发送出去。
//
FillChar(Buf, SizeOf(Buf), 0);
Ptr := @Buf[0];

Move(ipHdr, ptr^, SizeOf(ipHdr)); IncPtr(SizeOf(ipHdr));
Move(udpHdr, ptr^, SizeOf(udpHdr)); IncPtr(SizeOf(udpHdr));
Move(StrMessage[1], ptr^, length(StrMessage));


remote.sin_family := AF_INET;
remote.sin_port := htons(iToPort);
remote.sin_addr.s_addr := dwToIP;
end;

procedure TForm1.SendIt;
Var
sh : TSocket;
bOpt : Integer;
ret : Integer;
Buf : TPacketBuffer;
Remote : TSockAddr;
Local : TSockAddr;
iTotalSize : Word;
wsdata : TWSAdata;

begin
// Startup Winsock 2
ret := WSAStartup($0002, wsdata);
if ret<>0 then begin
memo1.lines.add('WSA Startup failed.');
exit;
end;
with memo1.lines do begin
add('WSA Startup:');
add('Desc.: '+wsData.szDescription);
add('Status: '+wsData.szSystemStatus);
end;

try
// Create socket
sh := Socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if (sh = INVALID_SOCKET) then begin
memo1.lines.add('Socket() failed: '+IntToStr(WSAGetLastError));
exit;
end;
Memo1.lines.add('Socket Handle = '+IntToStr(sh));

// Option: Header Include
bOpt := 1;
ret := SetSockOpt(sh, IPPROTO_IP, IP_HDRINCL, @bOpt, SizeOf(bOpt));
if ret = SOCKET_ERROR then begin
Memo1.lines.add('setsockopt(IP_HDRINCL) failed: '+IntToStr(WSAGetLastError));
exit;
end;

// Build the packet
BuildHeaders( SrcIP, SrcPort,
DestIP, DestPort,
'THIS IS A TEST PACKET',
Buf, Remote, iTotalSize );

// Send the packet
ret := SendTo(sh, buf, iTotalSize, 0, Remote, SizeOf(Remote));
if ret = SOCKET_ERROR then
Memo1.Lines.Add('sendto() failed: '+IntToStr(WSAGetLastError))
else
Memo1.Lines.Add('send '+IntToStr(ret)+' bytes.');

// Close socket
CloseSocket(sh);
finally
// Close Winsock 2
WSACleanup;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
SendIt;
end;

end.


?CopyRight 2000-2001
 
怎样才能实现组播功能?
 
用WINSOCK API很容易实现,INDY还有对应的控件。
 
unit MulticastSocket;

{
* 多址广播控件
* 本文件提取自 U_UDPSock.pas
* 整理于2001年11月17~2001年11月18日
* 关于 NB30 单元,主要用于
* "取得本地计算机所有的MAC地址"
* procedure LocalMAC(slMac : TStringList);
* 所以被我注释掉了
* 并不影响使用
}

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
WinSock;//, NB30;

const
MINBUFFERSIZE = 2048;
DEFAULTBUFFERSIZE = 16384;
MAXBUFFERSIZE = 63488; //62*1024
MULTICAST_TTL = IP_DEFAULT_MULTICAST_TTL;
MAX_MULTICAST_TTL = 128;

type
PIP_mreq = ^TIP_mreq;
TIP_mreq = record
imr_multiaddr : in_addr;
imr_interface : in_addr;
end;

TAPInAddr = Array [0..10] of PInAddr; // array of pInaddr
PAPInAddr = ^TAPInaddr; // pointer of Array

(*
PASTAT = ^TASTAT;
TASTAT = record
adapter : TAdapterStatus;
name_buf : TNameBuffer;
end;
*)

TUDPOnRecv = procedure (buffer: Pointer; len: integer; fromIP: string; fromPort: u_Short) of Object;

//接收数据线程
TUDPRecvThd = class(TThread)
private
fSocks : TSocket;
fBufSize : integer;
fOnRecv : TUDPOnRecv;
protected
procedure Execute ; override;
public
constructor Create(var Socks : TSocket; OnRecv : TUDPOnRecv; BufSize : integer);
end;

type
TMulticastSocket = class(TComponent)
private
{ Private declarations }
fActived : Boolean; {是否激活}

fsock : TSocket; {socket}
fRecvThd : TUDPRecvThd; {接收线程}
fMCReq : TIP_mreq; {记录加入的组地址,释放资源时用}
fSendBufSize: integer; {发送缓冲区大小}
fRecvBufSize: integer; {接收缓冲区大小}
fLocalIP : String; {本地IP地址}
fAddrTo : TSockAddr; {发送IP地址}
fCanRead : Boolean; {可以读取数据}
fCanWrite : Boolean; {可以发送数据}
fTTL : integer; {Time To Live,生存时间,即可以跨越的网关数}
fGroupAddress:String; {组地址}
fGroupPort : integer; {组端口}
//fRecvState : Boolean; {接收线程是否启动}
fOnRecv : TUDPOnRecv; {响应的事件}

{组地址}
procedure SetGroupAddress(addr:String);
{组端口}
procedure SetGroupPort(port:integer);
{读}
procedure SetCanRead(CanRead:Boolean);
{写}
procedure SetCanWrite(CanWrite:Boolean);
{发送缓冲区大小}
procedure SetSendBufSize(SendBufSize:integer);
{接收缓冲区大小}
procedure SetRecvBufSize(RecvBufSize:integer);
{本地IP地址}
procedure SetLocalIP(addr:String);
{是否激活}
procedure SetActived(const Value: Boolean);
{Time To Live,生存时间,即可以跨越的网关数}
procedure SetTTL(const Value: integer);

{改变响应事件的限制}
//procedure SetOnRecv(const Value: Boolean);
procedure SetOnRecv(const Value: TUDPOnRecv);

{Local IP set valid?}
{参数为''的话,就得到默认IP}
function LocalIPValid(var LocalIP:String) : Boolean;

{设置Socket可以接收数据}
function EnabledListen:Boolean;
{设置Socket不能接收数据}
procedure DisabledListen;
{设置Socket可以发送数据}
function EnabledSend:Boolean;
protected
{ Protected declarations }
public
{ Public declarations }
function Close:Boolean;
function Send(buffer : Pointer; len : integer ; Flag : integer = 0) : Boolean;
function AddToGroup : integer;
procedure StartReceive;

{取得本地计算机所有的IP地址}
procedure LocalIPs(slIPs : TStringList);
{取得本地计算机所有的MAC地址}
//procedure LocalMAC(slMac : TStringList);

function Connect:Boolean;
function DisConnect:Boolean;
published
{ Published declarations }
property LocalAddress : String read fLocalIP write SetLocalIP nodefault;
property CanRead : Boolean read fCanRead write SetCanRead default true;
property CanWrite : Boolean read fCanWrite write SetCanWrite default true;
property TTL : integer read fTTL write SetTTL default MULTICAST_TTL;
property SendBufSize: integer read fSendBufSize write SetSendBufSize default DEFAULTBUFFERSIZE;
property RecvBufSize: integer read fRecvBufSize write SetRecvBufSize default DEFAULTBUFFERSIZE;
property GroupAddress:String read fGroupAddress write SetGroupAddress nodefault;
property GroupPort:integer read fGroupPort write SetGroupPort default 6000;
property Actived:Boolean read fActived write SetActived default False;

property OnDataArrive:TUDPOnRecv read fOnRecv write SetOnRecv nodefault;

constructor Create(AOwner:TComponent);override;
destructor Destroy;override;
end;

procedure Register;

implementation

var
wsData : TWSAData;

procedure Register;
begin
RegisterComponents('FastNet', [TMulticastSocket]);
end;

{ TMulticastSocket }

function TMulticastSocket.AddToGroup:integer;
var
nReuseAddr : integer;
SockAddrLocal : TSockAddr;
pPE : PProtoEnt;
begin
Result:=-1;

pPE := GetProtoByName('UDP');
//Create Socket
fSock := Socket(AF_INET, SOCK_DGRAM, pPE.p_proto);
if fSock = INVALID_SOCKET then
Exit;

nReuseAddr := 1;
if SetSockOpt(fSock, SOL_SOCKET, SO_REUSEADDR, @nReuseAddr, SizeOf(integer)) = SOCKET_ERROR then
begin
CloseSocket(fSock);
Exit;
end;

//Set Local Address and bind
FillChar(SockAddrLocal, SizeOf(SockAddrLocal), 0);
SockAddrLocal.sin_family := AF_INET;
//发送用0
//SockAddrLocal.sin_port := htons(0);
SockAddrLocal.sin_port := htons(fGroupPort);
SockAddrLocal.sin_addr.S_addr := Inet_Addr(PChar(fLocalIP));
if Bind(fSock, SockAddrLocal, SizeOf(SockAddrLocal)) = SOCKET_ERROR then
begin
CloseSocket(fSock);
Exit;
end;

if fCanWrite then
if not EnabledSend then
Exit;

if fCanRead then
if not EnabledListen then
Exit;

Result:=0;
end;

function TMulticastSocket.Close: Boolean;
begin
//MulticastReceiver
//Exception will be? :( I don't know
//释放接收数据线程
if fRecvThd <> nil then
begin
fRecvThd.Suspend;
fRecvThd.Free;
fRecvThd := nil;
end;

DisabledListen;
//Close Socket
CloseSocket(fSock);
Result:=True;
end;

constructor TMulticastSocket.Create(AOwner:TComponent);
begin
{这里设置默认属性,我不知道为什么在Default中写的没有效果}
LocalIPValid(fLocalIP);
fCanRead:=True;
fCanWrite:=True;
fSendBufSize:=DEFAULTBUFFERSIZE;
fRecvBufSize:=DEFAULTBUFFERSIZE;
fGroupAddress:='225.0.0.1';
fGroupPort:=6000;
fTTL:=MULTICAST_TTL;
inherited Create(AOwner);
end;

destructor TMulticastSocket.Destroy;
begin
Close;
inherited Destroy;
end;

procedure TMulticastSocket.SetGroupAddress(addr: String);
var
nMCAddr : Cardinal;
begin
if Actived=True then
Exit;

//Multicast address valid?
nMCAddr := ntohl(inet_addr(PChar(addr)));
//though Multicast ip is between 224.0.0.0 to 239.255.255.255
//the 224.0.0.0 to 224.0.0.225 ips are reserved for system
if not ((nMCAddr <= $efffffff) and (nMCAddr >= $e0000100)) then
Exit;
fGroupAddress:=addr;
end;

function TMulticastSocket.Send(buffer:Pointer;len:integer;Flag:integer=0):Boolean;
begin
Result := False;
if not CanWrite then
Exit;
if SendTo(fSock, buffer^, len, Flag{MSG_DONTROUTE}, fAddrTo,
SizeOf(fAddrTo)) <> SOCKET_ERROR then
Result := True;
end;

procedure TMulticastSocket.StartReceive;
begin
if fRecvThd<> nil then
//接收线程已经启动
Exit;
//启动接收线程
if Assigned(fOnRecv) then
fRecvThd := TUDPRecvThd.Create(fSock, fOnRecv, fSendBufSize);
end;

procedure TMulticastSocket.SetCanRead(CanRead: Boolean);
begin
//if Actived=True then
// Exit;
if fCanRead=CanRead then
Exit;

if CanRead then
begin
if not EnabledListen then
Exit;
end else
DisabledListen;

fCanRead:=CanRead;
end;

procedure TMulticastSocket.SetCanWrite(CanWrite: Boolean);
begin
if Actived=True then
Exit;

fCanWrite:=CanWrite;
end;

procedure TMulticastSocket.SetGroupPort(Port: integer);
begin
if Actived=True then
Exit;

fGroupPort:=Port;
end;

procedure TMulticastSocket.SetRecvBufSize(RecvBufSize: integer);
begin
if Actived=True then
Exit;

//Buffer Size Valid?
if not ((RecvBufSize <= MAXBUFFERSIZE) and (RecvBufSize >= MINBUFFERSIZE)) then
Exit;
fRecvBufSize:=RecvBufSize;
end;

procedure TMulticastSocket.SetSendBufSize(SendBufSize: integer);
begin
if Actived=True then
Exit;

//Buffer Size Valid?
if not ((SendBufSize <= MAXBUFFERSIZE) and (SendBufSize >= MINBUFFERSIZE)) then
Exit;
fSendBufSize:=SendBufSize;
end;

function TMulticastSocket.LocalIPValid(var LocalIP:String): Boolean;
var
i : integer;
slLocalIPs : TStringList;
begin
Result := False;
slLocalIPs := TStringList.Create;
Self.LocalIPs(slLocalIPs);
if slLocalIPs.Count = 0 then
begin
slLocalIPs.Free;
Exit;
end;

if LocalIP = '' then
begin
LocalIP := slLocalIPs[0]; //Default Interface
Result := True;
end else
for i:=0 to slLocalIPs.Count-1 do
if Trim(slLocalIPs) = Trim(LocalIP) then
begin
Result := True;
Break;
end;
slLocalIPs.Free;
end;

procedure TMulticastSocket.SetLocalIP(addr: String);
begin
if Actived=True then
Exit;

//Local IP set valid?
if not LocalIPValid(addr) then
Exit;
fLocalIP:=addr;
end;

procedure TMulticastSocket.LocalIPs(slIPs: TStringList);
var
strLocalHost : string;
pHE : PHostent;
pInAd : PAPInAddr;
saLocal : TSockAddr;
i : integer;
begin
SetLength(strLocalHost, 255);
if GetHostName(PChar(strLocalHost), 254) = SOCKET_ERROR then
Exit;

pHE := GetHostByName(PChar(strLocalHost));
pInAd := PAPInAddr(pHE^.h_addr_list);
saLocal.sin_addr := (pInAd^[0]^);
i := 0;
while True do
begin
slIPs.Add(inet_ntoa(saLocal.sin_addr));
i := i + 1;
if(pInAd^ <> nil) then
saLocal.sin_addr := (pInAd^^) //local host
else
break;
end;
end;

(*
procedure TMulticastSocket.LocalMAC(slMac: TStringList);
var
ncb : TNCB;
adapt : TASTAT;
lanaEnum : TLanaEnum;
i, j : integer;
strPart, strMac : string;
begin
FillChar(ncb, SizeOf(TNCB), 0);
ncb.ncb_command := Char(NCBEnum);
ncb.ncb_buffer := PChar(@lanaEnum);
ncb.ncb_length := SizeOf(TLanaEnum);
Netbios(@ncb);

for i := 0 to integer(lanaEnum.length)-1 do
begin
FillChar(ncb, SizeOf(TNCB), 0);
ncb.ncb_command := Char(NCBReset);
ncb.ncb_lana_num := lanaEnum.lana;
Netbios(@ncb);

FillChar(ncb, SizeOf(TNCB), 0);
ncb.ncb_command := Chr(NCBAstat);
ncb.ncb_lana_num := lanaEnum.lana;
ncb.ncb_callname := '* ';
ncb.ncb_buffer := PChar(@adapt);
ncb.ncb_length := SizeOf(TASTAT);
if Netbios(@ncb) = Chr(0) then
begin
strMac := '';
for j := 0 to 5 do
begin
strPart := IntToHex(integer(adapt.adapter.adapter_address[j]), 2);
strMac := strMac + strPart + '-';
end;
SetLength(strMac, Length(strMac)-1);
slMac.Add(strMac);
end;
end;
end;*)

procedure TMulticastSocket.SetActived(const Value: Boolean);
begin
if Value=fActived then
//状态未发生变化
Exit;
if Value then
Connect
else
DisConnect;
end;

function TMulticastSocket.Connect: Boolean;
begin
Result:=(AddToGroup=0);
if not Result then
Exit;
if CanRead and Assigned(fOnRecv) then
StartReceive;
fActived:=Result;
end;

function TMulticastSocket.DisConnect: Boolean;
begin
Result:=Close;
if Result then
fActived:=False;
end;

procedure TMulticastSocket.SetOnRecv(const Value: TUDPOnRecv);
begin
if Actived and Assigned(fOnRecv) then
//事件已经在运行了
Exit;
fOnRecv := Value;
if Actived then
//已经激活但未设置事件
StartReceive;
end;

procedure TMulticastSocket.SetTTL(const Value: integer);
begin
if Actived
or (Value>MAX_MULTICAST_TTL)
or (Value<0) then
Exit;
fTTL := Value;
end;

function TMulticastSocket.EnabledListen : Boolean;
var
MCReq : TIP_mreq;
begin
Result:=False;

{接收数据缓冲区大小}
if SetSockOpt(fSock, SOL_SOCKET, SO_RCVBUF, @fRecvBufSize, SizeOf(integer)) = SOCKET_ERROR then
begin
CloseSocket(fSock);
Exit;
end;

{加入多址广播组}
MCReq.imr_multiaddr.S_addr := Inet_Addr(PChar(fGroupAddress));
MCReq.imr_interface.S_addr := Inet_Addr(PChar(fLocalIP));
if SetSockOpt(fSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, @MCReq,
SizeOf(TIP_mreq)) = SOCKET_ERROR then
begin
CloseSocket(fSock);
Exit;
end;
fMCReq := MCReq;

if Actived and Assigned(fOnRecv) then
StartReceive;

Result:=True;
end;

function TMulticastSocket.EnabledSend: Boolean;
var
SockAddrLocal, SockAddrRemote : TSockAddr;
begin
Result:=False;

FillChar(SockAddrLocal, SizeOf(SockAddrLocal), 0);
SockAddrLocal.sin_family := AF_INET;
SockAddrLocal.sin_port := htons(fGroupPort);
SockAddrLocal.sin_addr.S_addr := Inet_Addr(PChar(fLocalIP));

{发送数据缓冲区大小}
if SetSockOpt(fSock, SOL_SOCKET, SO_SNDBUF, @fSendBufSize, SizeOf(integer)) = SOCKET_ERROR then
begin
CloseSocket(fSock);
Exit;
end;
{IP multicast output interface}
if SetSockOpt(fSock, IPPROTO_IP, IP_MULTICAST_IF, @(SockAddrLocal.sin_addr),
SizeOf(In_Addr)) = SOCKET_ERROR then
begin
CloseSocket(fSock);
Exit;
end;
{设置Time To Livw}
if SetSockOpt(fSock, IPPROTO_IP, IP_MULTICAST_TTL, @fTTL, SizeOf(integer)) = SOCKET_ERROR then
begin
CloseSocket(fSock);
Exit;
end;

{设置发送的目的位置到fAddrTo中}
FillChar(SockAddrRemote, SizeOf(SockAddrRemote), 0);
SockAddrRemote.sin_family := AF_INET;
SockAddrRemote.sin_port := htons(fGroupPort);
SockAddrRemote.sin_addr.S_addr := Inet_Addr(PChar(fGroupAddress));
fAddrTo := SockAddrRemote;

Result:=True;
end;

procedure TMulticastSocket.DisabledListen;
begin
SetSockOpt(fSock, IPPROTO_IP, IP_DROP_MEMBERSHIP, @fMCReq, SizeOf(fMCReq));
end;

{ TUDPRecvThd }

constructor TUDPRecvThd.Create(var Socks: TSocket; OnRecv: TUDPOnRecv;
BufSize: integer);
begin
fSocks := Socks;
fOnRecv := OnRecv;
fBufSize := BufSize;
FreeOnTerminate := True;
inherited Create(False);
end;

procedure TUDPRecvThd.Execute;
var
readFDs : TFDSet;
nRecved, nAddrLen: integer;
buf : array [0..MAXBUFFERSIZE] of Byte;
SockFrom : TSockAddr;
begin
Priority := tpHighest;
while not Terminated do
begin
nAddrLen := SizeOf(SockFrom);
FD_ZERO(readFDs);
FD_SET(fSocks, readFDs);
Select(0, @readFDs, nil, nil, nil);
if FD_ISSET(fSocks, readFDs) then
begin
nRecved := RecvFrom(fSocks, buf, fBufSize, 0, SockFrom, nAddrLen);
if Assigned(fOnRecv) then
fOnRecv(@buf, nRecved, string(Inet_Ntoa(SockFrom.sin_addr)),
Cardinal(Ntohs(SockFrom.sin_port)));
end;
end;
end;

initialization
if WSAStartup(MakeWord(2,0), wsData)<>0 then
raise Exception.Create('Cannot use the socket service!');

finalization
WSACleanup;

end.
 
我使用了这个控件,在局域网中是可以发送和接收的,但是在互联网上收不到
这是什么原因?
 
我在局域使用时(不同的网段),发送方只需要调用MulticastSocket.Actived:=True;
接收方也只要调用MulticastSocket.Actived:=True;
就可以了,在互联网上就收不到
请大家告诉我是怎么回事?
 
to truest9
在互联网上使用组播,需要网络设备的支持.
 
不会
希望有高手回答
 
后退
顶部