Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 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); // !!! &#207;&#206;&#208;&#210; &#207;&#208;&#206;&#209;&#203;&#211;&#216;&#200;&#194;&#192;&#205;&#200;&#223; &#209;&#197;&#208;&#194;&#197;&#208;&#192;!!!
 sin_addr.S_addr:=INADDR_ANY;
 end;
if not errortest(bind(fhandle,adr,sizeof(adr)))
then
 begin
 wsaasyncselect(fhandle,HwndF,WM_SOCKET,FD_READ);
 // !!! &#199;&#196;&#197;&#209;&#220; form1.form.Handle - &#244;&#238;&#240;&#236;&#224;,
 //&#234;&#238;&#242;&#238;&#240;&#238;&#233; &#225;&#243;&#228;&#229;&#242; &#239;&#238;&#241;&#235;&#251;&#224;&#242;&#252;&#241;&#255; WM_SOCKET &#239;&#240;&#232; &#239;&#238;&#235;&#243;&#247;&#229;&#237;&#232;&#232; &#228;&#224;&#237;&#237;&#251;&#245;
 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.032 c
1-1103896028
digger
2004-12-24 16:47
2005.01.16
Отладка dll


8-1097356869
D5_User
2004-10-10 01:21
2005.01.16
Как проще сделать зуминг?


1-1104265046
RedLord
2004-12-28 23:17
2005.01.16
установка RXlib 2.75 под delphi 7


1-1104474929
begin...end
2004-12-31 09:35
2005.01.16
PByteArray: непонятности


6-1098888843
boban
2004-10-27 18:54
2005.01.16
Приложение видит, юзер - нет. Как сделать ?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский