用socket api怎么实现局域网广播?(50分)

  • 主题发起人 主题发起人 coolingxyz
  • 开始时间 开始时间
to yeath:
你给的例子是TCP,不能广播的。用UDP,我上面已经给出了代码。
---------------------------------------------------------------------
经常有这样的问题,我把广播的问题讲得清楚些。

广播有两种,
一种是directed broadcast,比如你的网段是192.168.0.X,你就往192.168.0.255发就可以了。
另一种是limited broadcast,广播地址是255.255.255.255

limited broadcast需要做一个SetSockopt():
broadcast:integer;;
broadcast:=1;
SetSockopt(FSocket,SOL_SOCKET,SO_BROADCAST, @broadcast,sizeof(broadcast));

两者都是可以的。
directed broadcast不需要SetSockopt(),以标准的C类网为例,直接发送x.x.x.255就可以了,
这种广播只有同一逻辑子网中的机器才能收到,也就是说对方地址应该是x.x.x.y,如果不是
即使在同一物理子网中也是收不到的。当然,这和子网掩码有关。

limited broadcast必须有SetSockopt(FSocket,SOL_SOCKET,SO_BROADCAST, @broadcast,sizeof(broadcast));
它的广播地址是255.255.255.255,它的好处是只要在同一子网中的主机,就可以收到这种
广播,而不必非要在统一逻辑子网中,例如,如果你的地址是x.x.x.1,那么这种广播,
地址是x.y.z.a的主机也能收到。
 
是的,没错,我给的是TCP/IP协议的。
 
TCP/IP是一个协议族。TCP、UDP都是其中的组成部分,IP位于它们之下。

+------+ +-----+ +-----+ +-----+
|Telnet| | FTP | | TFTP| ... | ... |
+------+ +-----+ +-----+ +-----+
| | | |
+-----+ +-----+ +-----+
| TCP | | UDP | ... | ... |
+-----+ +-----+ +-----+
| | |
+--------------------------+----+
| Internet Protocol & ICMP | (Internet Protocol就是IP 协议)
+--------------------------+----+
|
+---------------------------+
| Local Network Protocol |
+---------------------------+

Protocol Relationships
 
我还是没有调通呀,我是这么写的,现在。

procedure TFrmMain.madeSocket;//
var
optval : integer;
begin
If WSAStartup(MAKEWORD(2,2), MyWSA) <> 0 Then
Begin
WSACleanup;
MessageDlg('³õʼ»¯ Socket ³ö´í¡£', mtError, [mbYes], 0);
Exit;
end;
hSocket := Socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
If hSocket = INVALID_SOCKET Then
Begin
WSACleanup;
MessageDlg('³õʼ»¯ Socket ³ö´í¡£', mtError, [mbYes], 0);
Exit;
End;
{·¢ËÍ·½SocketAddr°ó¶¨}
Svr.sin_family := AF_INET;
Svr.sin_port := htons(LPort);
Svr.sin_addr.S_addr := INADDR_ANY;
If Bind(hSocket, Svr, SizeOf(Svr)) = SOCKET_ERROR Then
Begin
CloseSocket(hSocket);
WSACleanup;
MessageDlg('°ó¶¨¶Ë¿Ú '+IntToStr(LPort)+' ³ö´í!', mtError, [mbYes], 0);
Exit;
end;

optval := 1;
if (Setsockopt(hSocket, SOL_SOCKET, SO_BROADCAST, pchar(@optval), sizeof(optval)) = SOCKET_ERROR) then
begin
CloseSocket(hSocket);
WSACleanup;
MessageDlg('°ó¶¨¶Ë¿Ú '+IntToStr(LPort)+' ²»ÄܽøÐй㲥!', mtError, [mbYes], 0);
Exit;
end;

new(Cmd);
FillCommand(68, Cmd);
myudpSocket := TmyudpSocket.Create(false, hSocket, cmd, FrmMain.Handle);//recvfrom thread
end;



function TFrmMain.FillCommand(CmdType: Byte; Cmmd: PCommand):Boolean;
begin
if Cmmd.Ready then
begin
Case CmdType of
68:
begin
Cmmd^.CmdBuff[0] := 68;
Cmmd^.CmdBuff[1] := 60;
Cmmd^.CmdBuff[2] := 0;
Cmmd^.CmdBuff[3] := 0;
Cmmd^.CmdLen := 4;
Cmmd^.Ready := True;
end;
end;
Result := True;
end else
begin
Result := False;
end;
end;




procedure Tmyudpsocket.Execute;
var
i : Integer;
sockTo : Sockaddr_in;
begin
{ Place thread code here }
FreeOnTerminate := True;
sendmsg('Run');
while Not Terminated do
begin //jie shou shu ju
if Cmd.Ready then
begin
sockTo.sin_addr.S_addr := INADDR_BROADCAST;
len := SendTo(hsocket, cmd^.CmdBuff, Cmd^.CmdLen, 0, SockTo, Cmd^.ToLen);
// Cmd.Ready := False;
end;
if Not myDealWithData[j].Suspended then
begin
repeat
inc(j);
j := j mod 21;
sendmsg(IntTostr(j));
until myDealWithData[j].Suspended;
end;
myUdpData[j].data_len := recvFrom(hsocket,myUdpData[j].buff,buffsize,0,myUdpData[j].SockFrom,socksize);
if myUdpData[j].data_len > 0 then
begin
myDealWithData[j].Resume; // call DealWithData
sendmsg('myDealWithData['+IntTostr(j)+'].Resume;');
end;
end;

For i := 0 to 20 do
begin
myDealWithData.Terminate;
end;
end;

 
代码太长,不太想看。我把一个例子程序上传到:
http://www.playicq.com/dispdoc.php?id=2255
你可以去下载。
 
非常感谢,我已经下载来了。
 
多人接受答案了。
 
后退
顶部