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

  • 主题发起人 主题发起人 coolingxyz
  • 开始时间 开始时间
C

coolingxyz

Unregistered / Unconfirmed
GUEST, unregistred user!
FSockAddrIn.SIn_Addr.S_addr := inet_addr(PChar('255.255.255.255')); ;
FSockAddrIn.SIn_Port := htons(strtoint('8888'));
Sendto(sock,tmp1.memory^,tmp1.Size,0,FSockAddrIn,sizeof(FSockAddrIn));


这样好象不行哎。该怎么写呢?
 
前面是你的IP,最后一个是255,这样试试,行不行???
比如:192.168.0.255,UDP这样是可以的,TCP没试过。
 
procedure TFrmMain.madeHsocket;//socket初始化
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;
Svr.sin_family := AF_INET;
Svr.sin_port := htons(LPort);
Svr.sin_addr.S_addr := INADDR_ANY;//inet_addr(PChar('127.0.0.1'));
If Bind(hSocket, Svr, SizeOf(Svr)) = SOCKET_ERROR Then
Begin
CloseSocket(hSocket);
WSACleanup;
MessageDlg('°ó¶¨¶Ë¿Ú '+IntToStr(LPort)+' ³ö´í!', mtError, [mbYes], 0);
Exit;
end;
new(Cmd);
FillCommand(68, Cmd);
myudpSocket := TudpSocket.Create(false, hSocket, cmd, FrmMain.Handle);//recvfrom thread
end;



procedure TFrmMain.emailClick(Sender: TObject);//发送udp包
var
FSockAddrIn : Sockaddr_in;
buff : array[0..3] of Byte;
begin
FSockAddrIn.SIn_Addr.S_addr := inet_addr(PChar('192.168.2.1')); ;
FSockAddrIn.SIn_Port := htons(strtoint('1025'));
sendto(hsocket, Buff, 4, 0, FSockAddrIn, sizeof(FSockAddrIn));
end;


我用netspy来监听,根本没有包发送出去。
但recvFrom(hsocket,myUdpData[j].buff,buffsize,0,myUdpData[j].SockFrom,socksize);能收到别的机器发来的数据包。


请大家帮我看看。谢谢了。
 
能收到不就行了,你要监听到干什么???捕包工具还是netXRay好。
 
关键是发送不可以呀。老兄!那我就不能完成我的程序了。我需要跟别的程序通信的。不能发信息,怎么办??
 
你看一下你的
var
len
len=sendto(),返回的值是多少,然后到MSDN里查一下,就可以知道为什么没发出去了呀
在说原因呀
 
len := -1;了。

to cjsam 能把你的qq告诉我吗?我有问题问你。谢谢。我的是21156410。
 
不好意思,我公司里上不了QQ,他把SOCKET代理关了,有什么问题?我如果知道的没问题
,大家互相探讨了。
 
procedure TFrmMain.emailClick(Sender: TObject);//发送udp包
var
FSockAddrIn : Sockaddr_in;
buff : array[0..3] of Byte;
begin
FSockAddrIn.SIn_Addr.S_addr := inet_addr(PChar('192.168.2.1')); ;
FSockAddrIn.SIn_Port := htons(strtoint('1025'));
sendto(hsocket, Buff, 4, 0, FSockAddrIn, sizeof(FSockAddrIn));
end;
你的Buff里有数据吗?
 
有数据的时候也不行。发不出去。
而且我想发255.255.255.255的。就是同一个我网段进行广播。
 
同一个网段的好象应该用 yeath 说的那样。
发送应该没问题,你看看zw84611老兄的例程吧,就是一个广播发送,能行的。
源程序在:http://www.playicq.com/dispdoc.php?t=&id=434

 
我把整个代码贴上来,你帮我看看。
procedure TFrmMain.madeSocket;//初始化socket
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;
Svr.sin_family := AF_INET;
Svr.sin_port := htons(LPort);
Svr.sin_addr.S_addr := INADDR_ANY;//inet_addr(PChar('127.0.0.1'));
If Bind(hSocket, Svr, SizeOf(Svr)) = SOCKET_ERROR Then
Begin
CloseSocket(hSocket);
WSACleanup;
MessageDlg('°ó¶¨¶Ë¿Ú '+IntToStr(LPort)+' ³ö´í!', mtError, [mbYes], 0);
Exit;
end;
new(Cmd);
FillCommand(68, Cmd);
myudpSocket := TudpSocket.Create(false, hSocket, cmd, FrmMain.Handle);//recvfrom thread
end;

function TFrmMain.FillCommand(CmdType: Byte; Cmmd: PCommand):Boolean;//填充要发送的命令包
begin
Case CmdType of
68:
begin
Cmmd^.SockTo.sin_port := htons(RPort);
Cmmd^.SockTo.sin_addr.S_addr := Inet_addr(PChar('192.168.2.1'));
Cmmd^.CmdBuff[0] := 68;//¹ã²¥ÃüÁî
Cmmd^.CmdBuff[1] := 60;
Cmmd^.CmdBuff[2] := 0;
Cmmd^.CmdBuff[3] := 0;
Cmmd^.CmdLen := 4;
Cmmd^.ToLen := sizeof(Cmmd.SockTo);
Cmmd^.Ready := True;
end;
end;
end;

unit udp_Socket;//这是udp数据包接收和发送的线程

interface

uses
Classes, WinSock, messages, Windows, SysUtils, structure, DealWithData;

type
Tudpsocket = class(TThread)
private
{ Private declarations }
j : Integer;
len : Integer;
Cmd : PCommand;
hsocket : TSocket;
Handle: HWND;
socksize : integer;
buffsize : integer;
myUdpData : Array[0..20] of PUDPData;
myDealWithData : Array[0..20] of TDealWithData;
procedure sendmsg(str : string);
protected
procedure Execute; override;
public
constructor Create(RunStart : Boolean; sock : TSocket; Command: PCommand; FrmHandle: HWND);
end;

implementation

constructor Tudpsocket.Create(RunStart: Boolean; sock: TSocket; Command: PCommand; FrmHandle: HWND);
var
i : integer;
begin
j := 0;
hsocket := sock;
Handle := FrmHandle;
socksize := sizeof(myUdpData[0].sockFrom);
buffsize := length(myUdpData[0].buff);
Cmd := Command;
For i := 0 to 20 do
begin
new(myUdpData);
myDealWithData := TDealWithData.Create(True, @myUdpData, Handle);
end;
inherited Create(RunStart);
end;

procedure Tudpsocket.Execute;
var
i : Integer;
begin
{ Place thread code here }
FreeOnTerminate := True;
sendmsg('Run');
while Not Terminated do
begin //接收数据
if Cmd.Ready then//如果有命令已经填充,那么先发送这个命令包,在接收数据
begin
len := SendTo(hsocket, cmd.CmdBuff, Cmd.CmdLen, 0, Cmd.SockTo, Cmd.ToLen);
Cmd.Ready := False;
end;
{
FSockAddrIn.SIn_Addr.S_addr := inet_addr(PChar('192.168.2.1')); ;
FSockAddrIn.SIn_Port := htons(strtoint('1025'));
len := sendto(hsocket, cmd.CmdBuff, Cmd.CmdLen, 0, FSockAddrIn, sizeof(FSockAddrIn));
}
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;

procedure Tudpsocket.sendmsg(str: string);
begin
SendMessage(Handle, MY_addline, 0, Integer(PChar(str)));
end;

end.


麻烦了。
 
问题在于我有 数据填充后也不能被发送哎。
 
看不出来有什么问题,
把发送那一块提出来看,很简单,没什么问题呀,可以发送出去的。
 
那你先用不广播的形式发,能不能发出去???
 
Limited Broadcast,关键是要加这一句:
setsockopt(s,SOL_SOCKET,SO_BROADCAST,pchar(@optval),sizeof(optval))

给你个例子:

{
an example implement limited udp broadcast(255.255.255.255)
}

unit udp;

interface

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

const
WM_SOCK = WM_USER + 1; //自定义windows消息
UDPPORT = 6543; //设定UDP端口号

type
Tfrmmain = class(TForm)
Button1: TButton;
Edit1: TEdit;
Memo1: TMemo;
Edit2: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
s: TSocket;
addr: TSockAddr;
FSockAddrIn : TSockAddrIn;
//mreq:ip_mreq;
//利用消息实时获知UDP消息
procedure ReadData(var Message: TMessage); message WM_SOCK;
public
{ Public declarations }
procedure SendData(Content: String);
end;

var
frmmain: Tfrmmain;

implementation

{$R *.DFM}

procedure Tfrmmain.FormCreate(Sender: TObject);
var
TempWSAData: TWSAData;
optval: integer;
begin
// 初始化SOCKET
if WSAStartup($101, TempWSAData)=1 then
showmessage('StartUp Error!');

s := Socket(AF_INET, SOCK_DGRAM, 0);
if (s = INVALID_SOCKET) then //Socket创建失败
begin
showmessage(inttostr(WSAGetLastError())+' Socket创建失败');
CloseSocket(s);
//exit;
end;
//发送方SockAddr绑定
addr.sin_family := AF_INET;
addr.sin_addr.S_addr := INADDR_ANY;
addr.sin_port := htons(UDPPORT);
if Bind(s, addr, sizeof(addr)) <> 0 then
begin
showmessage('bind fail');
end;

optval:= 1;
if setsockopt(s,SOL_SOCKET,SO_BROADCAST,pchar(@optval),sizeof(optval)) = SOCKET_ERROR then
begin
showmessage('无法进行UDP广播');
end;

WSAAsyncSelect(s, frmmain.Handle , WM_SOCK, FD_READ);
//接收端SockAddrIn设定
FSockAddrIn.SIn_Family := AF_INET;
FSockAddrIn.SIn_Port := htons(UDPPORT);

label3.Caption := '端口:'+inttostr(UDPPORT);
end;

procedure Tfrmmain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
CloseSocket(s);
end;

procedure Tfrmmain.ReadData(var Message: TMessage);
var
buffer: Array [1..4096] of char;
len: integer;
flen: integer;
Event: word;
value: string;
begin
flen:=sizeof(FSockAddrIn);
FSockAddrIn.SIn_Port := htons(UDPPORT);
Event := WSAGetSelectEvent(Message.LParam);
if Event = FD_READ then
begin
len := recvfrom(s, buffer, sizeof(buffer), 0, FSockAddrIn, flen);
value := copy(buffer, 1, len);
Memo1.Lines.add(value)
end;
end;

procedure Tfrmmain.SendData(Content: String);
var
value{,hostname}: string;
len: integer;
begin
FSockAddrIn.SIn_Addr.S_addr := INADDR_BROADCAST;
//FSockAddrIn.SIn_Addr.S_addr := inet_addr(pchar(Edit1.text)); //INADDR_BROADCAST; //INADDR_BROADCAST = -1 ?
value := Content;
len := sendto(s, value[1], Length(value), 0, FSockAddrIn, sizeof(FSockAddrIn));
if (WSAGetLastError() <> WSAEWOULDBLOCK) and (WSAGetLastError() <> 0) then
showmessage(inttostr(WSAGetLastError()));
if len = SOCKET_ERROR then
showmessage('send fail');
if len <> Length(value) then
showmessage('Not Send all');
end;

procedure Tfrmmain.Button1Click(Sender: TObject);
begin
senddata(Edit2.text);
end;

end.
 
var
ConnectSocket:TSocket;
wData:WSADATA;
sock_addr:sockaddr_in;
iRet:Integer;
begin
Result := 0;
iRet := WSAStartup($0101,wData);
if iRet<>0 then
begin
Result := -1;
Application.MessageBox('初始化Winsock库时产生错误,请联系管理员!','提示信息',MB_ICONINFORMATION);
exit;
end;
ConnectSocket := socket(AF_INET,SOCK_STREAM,0);
if ConnectSocket=INVALID_SOCKET then
begin
Result := -1;
Application.MessageBox('创建Socket时产生错误,请联系管理员!','提示信息',MB_ICONINFORMATION);
Exit;
end;

sock_addr.sin_family := AF_INET;
sock_addr.sin_port := htons(iPort);
sock_addr.sin_addr.S_addr := inet_addr(PChar(ServerIP));
iret := connect(ConnectSocket,sock_addr,sizeof(sock_addr));
if iret<>0 then
begin
Result := 1;
Exit;
end;

WSAAsyncSelect(ConnectSocket,Self.Handle,WM_SOCKET,FD_READ or FD_ACCEPT or FD_CLOSE);//wm_socket通过RegisterWindowMessage获得
//主程序里对wndProc过程进行重载。
 
再在wndProc过程里捕获wm_socket,当有FD_READ事件发生里,调用recvfrom接收数据
再创建你的处理线程,进行处理。
 
谢谢大家。我晚上试试看。没有大家帮助真的不行呀。
 
直接用ICS的恐件也可以,不用覆盖什么WINPROC了,用FASTNET的也不错
 
后退
顶部