写了一个局域网版的五子棋,用到了组播技术,整理了一个控件代码,希望对初次使用组播技术的人有帮助。在D6下调试通过。
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, activeX;//, 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;