Форум: "Сети";
Текущий архив: 2005.01.16;
Скачать: [xml.tar.bz2];
ВнизUDP и множество сетевых интерфейсов Найти похожие ветки
← →
SkyNet (2004-10-27 03:35) [0]Здравствуйте мастера...
хочу задати один каверзный вопросец...
каким образом можно привязать UDP клиента (неважно какой компонент или winsock) к определённому IP адресу локального сетевого интерфейса...если интерфейс не один...если один то к определённому IP этого интерфейса...
заранее благодарен за пояснения...
← →
SkyNet (2004-10-27 03:40) [1]как извесно существует правило по которому выбирается сеть с более высоким приоритетом, классом А
а у нас сеть класса В
если ктото ставит ADSL либо прописывает дополнительный IP, UDP клиент отсылает текущий IP сети класса А...
чтото вроде 10.0.0.6 хотя должен 192.168.4.123
← →
Verg © (2004-10-27 06:59) [2]bind()
← →
Verg © (2004-10-27 07:02) [3]
> как извесно существует правило по которому выбирается сеть
> с более высоким приоритетом, классом А
> а у нас сеть класса В
> если ктото ставит ADSL либо прописывает дополнительный IP,
> UDP клиент отсылает текущий IP сети класса А...
> чтото вроде 10.0.0.6 хотя должен 192.168.4.123
Выбирается IP адрес того интерфейса, через который выбран путь по таблице маршрутизации до адреса назначения пакета.
← →
SkyNet (2004-10-28 00:44) [4]ага...понял спасиб...большое...
← →
SkyNet (2004-10-28 01:29) [5]
unit UDPSock;
interface
uses WinSock,windows,messages,SysUtils,dialogs;
var
wsadata:twsadata;
FHandle,FCHandle:TSocket;
inited:boolean=False;
procedure Listen(lport:integer;const PeerIP:string;HwndF:Hwnd);
procedure CreateSocket; // Èíèöèàëèçàöèÿ
procedure DestroySocket; // Çàêðûâàåì õýíäëû
function receivebuf(var buf:array of char):integer; // Ïðèèÿòü èíôîðìàöèþ
procedure SendPeer2Peer(var data;len:integer);
procedure SendPeer2PeerStr(str:string);
procedure StopServer;
{Ýòà ôóíêöèÿ äîëæíà âûçûâàòüñÿ ïðè ïîëó÷åíèè ôîðìîé ñîîáùåíèÿ WM_SOCKET Íàïðèìåð:
function TForm1.KOLForm1Message(var Msg:tagMSG;var Rslt:Integer):Boolean;
var
len: integer;
buf: array [1..2048] of byte;
begin
Result:=False;
case Msg.message
of
//..........
WM_SOCKET:
begin
len:=ReceiveBuf(buf); // Len - êîë-âî çàïèñàííûõ äàííûõ â áóôåð
end;
end;
end;}
implementation
function ErrorTest(const errcode:integer):boolean;
var
wsae:integer;
begin
result:=(errcode=SOCKET_ERROR)or(errcode=INVALID_SOCKET);
if result
then
begin
wsae:=wsagetlasterror;
if wsae<>WSAEWOULDBLOCK
then
begin
//showmessage("Network Error!");
end
else result := false;
end;
end;
procedure Listen(lport:integer;const PeerIP:string;HwndF:Hwnd);
var
adr:tsockaddr;
begin
fchandle:=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
if not errortest(fchandle)
then
begin
with adr
do
begin
sin_family:=AF_INET;
sin_port:=htons(lPort);
integer(sin_addr):=inet_addr(pchar(PeerIP));
end;
errortest(integer(adr.sin_addr));
errortest(winsock.connect(fchandle,adr,sizeof(adr)));
end;
//if fhandle<>SOCKET_ERROR then exit;
fhandle:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if not errortest(fhandle)
then
begin
with adr
do
begin
sin_family:=AF_INET;
sin_port:=htons(LPort); // !!! ÏÎÐÒ ÏÐÎÑËÓØÈÂÀÍÈß ÑÅÐÂÅÐÀ!!!
sin_addr.S_addr:=INADDR_ANY;
end;
if not errortest(bind(fhandle,adr,sizeof(adr)))
then
begin
wsaasyncselect(fhandle,HwndF,WM_SOCKET,FD_READ);
// !!! ÇÄÅÑÜ form1.form.Handle - ôîðìà,
//êîòîðîé áóäåò ïîñëûàòüñÿ WM_SOCKET ïðè ïîëó÷åíèè äàííûõ
end;
end;
end;
function receivebuf(var buf:array of char):integer;
begin
Result:=WinSock.recv(Fhandle,Buf,sizeof(buf),0);
end;
procedure SendPeer2PeerStr(str:string);
begin
SendPeer2Peer(str[1],length(str));
end;
procedure SendPeer2Peer(var data; len:integer);
begin
winsock.send(fchandle,Data,len,0);
end;
procedure CreateSocket;
begin
fhandle:=SOCKET_ERROR;
fcHandle:=SOCKET_ERROR;
wsastartup($202,wsadata);
Inited:=True;
bind(1,,15);
end;
procedure StopServer;
begin
winsock.closesocket(fhandle);
end;
procedure DestroySocket;
begin
if Inited
then
begin
winsock.closesocket(fhandle);
winsock.closesocket(fcHandle);
wsacleanup;
inited:=False;
end;
end;
end.
код который шлёт и принимает пакеты по UDP
← →
SkyNet (2004-10-28 01:30) [6]я так понимаю чтоб его привязать к определённому интерфейсу...нада в методе создания сокета пробиндить чтото с чемто.....а как это хоть примерно делается ???
← →
Verg © (2004-10-28 07:32) [7]Точно так же, как ты это делаешь с принимаеющим сокетом
После его создания.
> with adr
> do
> begin
> sin_family:=AF_INET;
> sin_port:= 0; // Порт задавать не обязательно
> sin_addr.S_addr:=<IP адрес нужного тебе интерфейса>;
> end;
> if not errortest(bind(fchandle,adr,sizeof(adr)))
> then
> begin
.........................................
.............................................
> end;
> end;
IP адреса интерфейсов можно получить при помощи GetIpAddrTable из IPHLPAPI.DLL
← →
Verg © (2004-10-28 08:04) [8]Кстати,
> procedure CreateSocket;
> begin
> fhandle:=SOCKET_ERROR; // INVALID_SOCKET ?
> fcHandle:=SOCKET_ERROR; // INVALID_SOCKET ?
> wsastartup($202,wsadata);
> Inited:=True;
> bind(1,,15);
> end
Поясни?
← →
SkyNet (2004-10-28 21:04) [9]Да это я тут пытался пробиндить сокет :) и забыл стереть ...это просто оставшийся мусор в коде.... :)
← →
SkyNet (2004-10-29 01:45) [10]дело в том что мне нужно принимать и отправлять широковещательные пакеты... и по заголовку пришедшего пакета определять IP удалённого компа..
если там множество интерфейсов...оно почему-то левый определяет...
я ужо замутил выбор сетевого интерфейса...
вот код...unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, ImgList, Winsock, IdBaseComponent,
IdComponent, IdUDPBase, IdUDPClient, IdUDPServer, IdSocketHandle,
IdAntiFreezeBase, IdAntiFreeze;
type
TForm1 = class(TForm)
Button1: TButton;
ComboBoxEx1: TComboBoxEx;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
ImageList1: TImageList;
Label6: TLabel;
Label7: TLabel;
Edit1: TEdit;
Label8: TLabel;
Label9: TLabel;
Label10: TLabel;
Label11: TLabel;
Label12: TLabel;
Label13: TLabel;
Label14: TLabel;
Button3: TButton;
ListBox1: TListBox;
UDPClient: TIdUDPClient;
UDPServer: TIdUDPServer;
IdAntiFreeze1: TIdAntiFreeze;
Button4: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure ComboBoxEx1Change(Sender: TObject);
procedure UDPServerUDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type TInterfacesList=record //тип данных для массива интерфейсов системы
IP,//:)
Mask,//Маска
Broadcast:string[15];//Широковещательный адрес
Status:string[20];//Статус интерфейса Up/Down
BroadcastSupp,//Поддерживается ли бродкаст
InterfCycle:boolean;//Цикличиский ли интерфейс...
end;
function EnumInterfaces:Boolean;
{функция WSAIOCtl импортируется из Winsock 2.0}
function WSAIoctl(
s:TSocket;
cmd:DWORD;
lpInBuffer:PCHAR;
dwInBufferLen:DWORD;
lpOutBuffer:PCHAR;
dwOutBufferLen:DWORD;
lpdwOutBytesReturned:LPDWORD;
lpOverLapped:POINTER;
lpOverLappedRoutine:POINTER):Integer; stdcall; external "WS2_32.DLL";
var
Form1:TForm1;
InterfacesList:array of TInterfacesList; //список интерфейсов
implementation
{$R *.dfm}
function EnumInterfaces:Boolean;
const
SIO_GET_INTERFACE_LIST=$4004747F;
IFF_UP=$00000001;
IFF_BROADCAST=$00000002;
IFF_LOOPBACK=$00000004;
IFF_POINTTOPOINT=$00000008;
IFF_MULTICAST=$00000010;
type sockaddr_gen=packed record
AddressIn:sockaddr_in;
filler:packed array[0..7]of char;
end;
type INTERFACE_INFO=packed record
iiFlags:u_long;//Флаги интерфейса
iiAddress:sockaddr_gen;//Адрес интерфейса
iiBroadcastAddress:sockaddr_gen;//Broadcast адрес
iiNetmask:sockaddr_gen;//Маска подсети
end;
var
s:TSocket;
wsaD:WSADATA;
NumInterfaces:Integer;
BytesReturned,SetFlags:u_long;
pAddrInet:SOCKADDR_IN;
pAddrString:PCHAR;
PtrA:pointer;
Buffer:array[0..20]of INTERFACE_INFO;
i:Integer;
begin
result:=true;//Инициализируем переменную
WSAStartup($0101,wsaD);//Запускаем WinSock
//Здесь можно дабавить различные обработчики ошибки :)
s:=Socket(AF_INET,SOCK_STREAM,0);//Открываем сокет
if(s=INVALID_SOCKET)
then exit;
try//Вызываем WSAIoCtl
PtrA:=@bytesReturned;
if(WSAIoCtl(s,SIO_GET_INTERFACE_LIST,nil,0,@Buffer,1024,PtrA,nil,nil)<>SOCKET_ERROR)
then
begin//Если OK, то определяем количество существующих интерфейсов
NumInterfaces:=BytesReturned div SizeOf(INTERFACE_INFO);
SetLength(InterfacesList,NumInterfaces);
for i:=0 to NumInterfaces-1
do// Для каждого интерфейса
begin
pAddrInet:=Buffer[i].iiAddress.addressIn;//IP адрес
pAddrString:=inet_ntoa(pAddrInet.sin_addr);
InterfacesList[i].IP:=pAddrString;
pAddrInet:=Buffer[i].iiNetMask.addressIn;//Маска подсети
pAddrString:=inet_ntoa(pAddrInet.sin_addr);
InterfacesList[i].Mask:=pAddrString;
pAddrInet:=Buffer[i].iiBroadCastAddress.addressIn;//Broadcast адрес
pAddrString:=inet_ntoa(pAddrInet.sin_addr);
InterfacesList[i].Broadcast:=pAddrString;
SetFlags:=Buffer[i].iiFlags;
if(SetFlags and IFF_UP)=IFF_UP
then InterfacesList[i].Status:="Interface UP"//Статус интерфейса up/down
else InterfacesList[i].Status:="Interface DOWN";
if(SetFlags and IFF_BROADCAST)=IFF_BROADCAST
then InterfacesList[i].BroadcastSupp:=true//Broadcasts - поддерживает или
else InterfacesList[i].BroadcastSupp:=false;//не поддерживается
if(SetFlags and IFF_LOOPBACK)=IFF_LOOPBACK
then InterfacesList[i].InterfCycle:=true //Циклический или
else InterfacesList[i].InterfCycle:=false;//нормальный
end;
end;
except
end;
//Закрываем сокеты
CloseSocket(s);
WSACleanUp;
result:=false;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
i,InCount:integer;
begin
EnumInterfaces;//Заполняем массив InterfacesList данными...
InCount:=length(InterfacesList);//Узнаём количество записей в списке;
if InCount<>0
then for i:=0 to InCount-1//заполняем выпадающий список ComboBoxEx1
do
begin
if InterfacesList[i].InterfCycle //если интерфейс циклический рисуем значёк !
then
begin
ComboBoxEx1.ItemsEx.Add.ImageIndex:=2;
ComboBoxEx1.ItemsEx.Items[i].Caption:=InterfacesList[i].IP;
end
else //если интерфейс не циклический
begin
if InterfacesList[i].Status="Interface UP" //если интерфейс включен
then ComboBoxEx1.ItemsEx.Add.ImageIndex:=0 //рисуем значёк 0
else ComboBoxEx1.ItemsEx.Add.ImageIndex:=1;//или рисуем значёк 1
ComboBoxEx1.ItemsEx.Items[i].Caption:=InterfacesList[i].IP;
end;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
application.Terminate;
end;
procedure TForm1.ComboBoxEx1Change(Sender: TObject);
var
j:integer;
begin //при выборе элемента списка...ищем и выводим данные...
for j:=0 to length(InterfacesList)-1
do if ComboBoxEx1.Text=InterfacesList[j].IP
then
begin
Label9.Caption:=InterfacesList[j].IP;
Label10.Caption:=InterfacesList[j].Mask;
Label11.Caption:=InterfacesList[j].Broadcast;
Label12.Caption:=InterfacesList[j].Status;
if InterfacesList[j].BroadcastSupp
then Label13.Caption:="Да"
else Label13.Caption:="Нет";
if InterfacesList[j].InterfCycle
then Label14.Caption:="Да"
else Label14.Caption:="Нет";
end;
end;
← →
SkyNet (2004-10-29 01:47) [11]но этот код всего-лиш забивает все имеющиеся интерфейсы в динамический массив....
можно ли использовать данные которые я получаю посредством этого кода...если да то как ?
← →
Verg © (2004-10-29 02:33) [12]
> дело в том что мне нужно принимать и отправлять широковещательные
> пакеты... и по заголовку пришедшего пакета определять IP
> удалённого компа..
Скорее всего, все дело в отправке бродкастов. А точнее в выборе сетевым ядром и-фейса отправителя на передающей стороне при формировании бродкастовой датаграммы.
Если у отправителя такой ДГ несколько сетевых (логических) инт-сов, замапленных на один физический (несколько IP адресов на одной сетевой карте), то в сеть отправляется одна (по крайней мере в Win2K) датаграмма с адресом-источника = выбранному по таблице маршрутизации адресом логич. и-фйса (к которому относится запись в маршрутной таблице Dst=255.255.255.255 и запись-то эта всего одна в Win2K сколько бы сетевых карт не стояло). Допустим, что эта датаграмма улетела в сеть с адресом источника таким, который не принадлежит ни одной подсети на и-фейсе приемного хоста (сервера).
Что произойдет. Приемник все равно примет эту датаграмму, т.к. адрес назначения ее = INADDR_BROADCAST. А в адресе источника получается как бы "левак", с точки зрения самого принявшего хоста.
Как быть?
А надо просто грамотно передавать броадкасты, а не преславутым INADDR_BROADCAST.
Эту датаграмму надо посылать через каждый сетевой интерфейс отдельно.
Для этого, в адресе назначения датаграммы (sendto) указывают бродкастовый адрес подсети, который равен
iface_IP[i] or not iface_NETMASK[i]. Где i = номер сет инт-са.
Физически в сети такие датаграммы будут распространятся точно так же, т.е. с MAC адресом ff:ff:ff:ff:ff:ff, но в IP заголовках будут указаны валидные адреса данной подсети. Что позволит приемному хосту отфильтровать их, а когда подходящая будет принята (RecvFrom), то и адрес источника у ней будет из доступной для приемника подсети.
При этом наоборот, передающий сокет ни в коем случае нельзя bind-ить.
← →
SkyNet (2004-10-30 00:19) [13]Грамотно изложено... :)
я так и предпологал... бродкаст один для всех интерфейсов...
можно немного уточнить как это реализовывается
I>
iface_IP[i] or not iface_NETMASK[i].
???
вот у меня массив:
type TInterfacesList=record //тип данных для массива интерфейсов системы
IP,//:)
Mask,//Маска
Broadcast:string[15];//Широковещательный адрес
Status:string[20];//Статус интерфейса Up/Down
BroadcastSupp,//Поддерживается ли бродкаст
InterfCycle:boolean;//Цикличиский ли интерфейс...
end;
array ilist of TInterfacesList;
...//тут я его заполнил
...//и получил допустим 3 IP адреса
{
ilist[1]
IP=192.168.4.123
Mask=255.255.255.0
Broadcast=255.255.255.255
ilist[2]
IP=10.0.0.1
Mask=255.0.0.0
Broadcast=255.255.255.255
ilist[3]
IP=10.0.0.2
Mask=255.0.0.0
Broadcast=255.255.255.255
}
← →
SkyNet (2004-10-30 00:21) [14]нужно передать датаграмму по бродкасту только на первый интерфейс... 4.123
игнорируя все остальные...
← →
Verg © (2004-10-30 13:46) [15]
> можно немного уточнить как это реализовывается
> I>
> iface_IP[i] or not iface_NETMASK[i].
> ???
> IP=192.168.4.123
> Mask=255.255.255.0
Адрес броадкаста подсети = IP or not Mask.
Я не врубаюсь, чес слово, что тут непонятно?
Может ты не поимаешь, что IPv4 адреса - это просто, 32-х разрядные числа?
Маски подсетей представляются так же....
← →
SkyNet (2004-10-30 18:08) [16]а...вот тото и оно что я не понял этого, теперь догоняю...:)
спасибо большое...!
вы мне очень помогли товарисчь Verg.
← →
Андрей 2004 (2004-10-30 19:21) [17]Вы бы не могли подсказать судя по первому коду при создании UDP-сокета порт на каком ему надо работать не обязательно или я не прав?
← →
SkyNet (2004-10-31 00:38) [18]вообщето порт сервера обязателен....
иначе он не поймает датаграмму посланную ему...
сервер слушает порт на предмет поступившего сигнала...
так что без порта непонятно как он вообще работать может...
Страницы: 1 вся ветка
Форум: "Сети";
Текущий архив: 2005.01.16;
Скачать: [xml.tar.bz2];
Память: 0.53 MB
Время: 0.047 c