Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Сети > Снова сокеты!


Автор: Dayana 4.2.2003, 19:30
У меня вот такая проблема. От одного устройства (модема) по лану приходят пакеты. Просматривая снифером, вижу порт, IP отправителя и IP получателя. Но они отличны от IP самого устройства и IP который определила в Local Area Connection. Это модуляция пакетов через модем. Задача получать эти пакеты. Открываю сокет TWSocket. Протокол udp, Addr = '0.0.0.0', т.е от любого клиента. И ставлю номер порта, который показал мне снифер. Т.к. протокол udp, то после соединения пользуюсь методом RecieveFrom, который получает пакет в буфер и также возвращает адрес отправителя.

Пакеты модем посылает, а сокет ничего не получает. Я с этим совсем мало работала. Может кто-нибудь знает в чем ошибка?

Код проверки пока такой
Код

 WSocket1.Addr := '0.0.0.0';
 WSocket1.Port := '5003';
 WSocket1.Proto := 'udp';
 WSocket1.Connect;
 Sleep(3000);
 for i := 1 to 3 do
 begin
//    WSocket1.Receive(@RcvMsg, 8024);
   WSocket1.ReceiveFrom(@RcvMsg, 8024, AddrSour, LengSourc);
 end


Спасибо!

Автор: Dayana 4.2.2003, 22:56
Я вот нашла, чтобы настроить сокет на прием пакетов, надо установить флаг PROMISC - установка режима перехвата на сетевой карте.
Есть исходники на С++. Там используются функции API. Может кто знает, как такой флаг установить, пользуясь TWSocket, и есть ли он там вообще?

Автор: Baa 4.2.2003, 23:02
А кто тебе мешает создать сокет руками через апи? без компонентов.
з.ы. с вероятностью в 99% могу сказать, что в твоем компоненте выставить PROMISC низя.

Автор: Medved 4.2.2003, 23:46
Да.... полностью с Baa согласен.... я сейчас тоже занимаюсь этими вопросами, и попробовав кучу компонентов, пришел к выводу, что лучше при работе с сокетами использовать API, это надежно, позволяет программировать без ограничений, хотя долго и утомительно....

Автор: Dayana 4.2.2003, 23:51
Baa, нашла такую ф-циюWSocket-ioctlsocket, которой передается handle на сокет, а также флаг который устанавливает режим перехвата. Этот флаг я взяла вот с этого кода

Цитата

#include <conio.h>
#include <stdio.h>
#include <winsock2.h>

#define MAX_PACKET_SIZE    0x10000
#define SIO_RCVALL        0x98000001
// Буфер для приёма данных
char Buffer[MAX_PACKET_SIZE]; // 64 Kb

//Структура заголовка IP-пакета

typedef struct IPHeader {
  UCHAR  iph_verlen;  // версия и длина заголовка
  UCHAR  iph_tos;      // тип сервиса
  USHORT  iph_length;  // длина всего пакета
  USHORT  iph_id;      // Идентификация
  USHORT  iph_offset;  // флаги и смещения
  UCHAR  iph_ttl;      // время жизни пакета
  UCHAR  iph_protocol; // протокол
  USHORT  iph_xsum;    // контрольная сумма
  ULONG  iph_src;      // IP-адрес отправителя
  ULONG  iph_dest;    // IP-адрес назначения
} IPHeader;

char src[10];
char dest[10];
char ds[15];
unsigned short lowbyte;
unsigned short hibyte;

void main()
{
  WSADATA    wsadata;  // Инициализация WinSock.
  SOCKET      s;        // Cлущающий сокет.
  char        name[128]; // Имя хоста (компьютера).
  HOSTENT*    phe;      // Информация о хосте.
  SOCKADDR_IN sa;        // Адрес хоста
  IN_ADDR sa1;        //
  unsigned long        flag = 1;  // Флаг PROMISC Вкл/выкл.

  // инициализация
  WSAStartup(MAKEWORD(2,2), &wsadata);
  s = socket( AF_INET, SOCK_RAW, IPPROTO_IP );
  gethostname(name, sizeof(name));
  phe = gethostbyname( name );
  ZeroMemory( &sa, sizeof(sa) );
  sa.sin_family = AF_INET;
  sa.sin_addr.s_addr = ((struct in_addr *)phe->h_addr_list[0])->s_addr;
  bind(s, (SOCKADDR *)&sa, sizeof(SOCKADDR));
 
  // Включение promiscuous mode.
  ioctlsocket(s, SIO_RCVALL, &flag);

  // Бесконечный цикл приёма IP-пакетов.
  while( !_kbhit() )
  {
    int count;
    count = recv( s, Buffer, sizeof(Buffer), 0 );
    // обработка IP-пакета
    if( count >= sizeof(IPHeader) )
    {
      IPHeader* hdr = (IPHeader *)Buffer;
      //Начинаем разбор пакета...

strcpy(src,"Пакет: ");
CharToOem(src,dest);
printf(dest);
// Преобразуем в понятный вид адрес отправителя.
printf("From ");
sa1.s_addr = hdr->iph_src;
printf(inet_ntoa(sa1));

// Преобразуем в понятный вид адрес получателя.
printf(" To ");
sa1.s_addr = hdr->iph_dest;
printf(inet_ntoa(sa1));

// Вычисляем протокол. Полный список этих констант
// содержится в файле winsock2.h
printf(" Prot: ");
if(hdr->iph_protocol == IPPROTO_TCP) printf("TCP ");
if(hdr->iph_protocol == IPPROTO_UDP) printf("UDP ");

// Вычисляем размер. Так как в сети принят прямой порядок
// байтов, а не обратный, то прийдётся поменять байты местами.
printf("Size: ");
lowbyte = hdr->iph_length>>8;
hibyte = hdr->iph_length<<8;
hibyte = hibyte + lowbyte;
printf("%s",itoa(hibyte,"",10));

// Вычисляем время жизни пакета.
printf(" TTL:%s",itoa(hdr->iph_ttl,"",10));
printf("\n");

    }
  }

  closesocket( s );
  WSACleanup();
}


И написала у себя вот так
Цитата

const
  CmdFlag : u_long = 1;
  SIO_RCVALL = $98000001;
begin         
  FillChar(RcvMsg, 8024, #0);
  WSocket1.Addr := '0.0.0.0';
  WSocket1.Port := '5003';
  WSocket1.LocalPort := '5003';
  WSocket1.Proto := 'udp';
  WSocket_ioctlsocket(WSocket1.HSocket, SIO_RCVALL, CmdFlag);
  WSocket1.Connect;
  Sleep(3000);
  for i := 1 to 3 do
  begin
    WSocket1.ReceiveFrom(@RcvMsg, 8024, AddrSour, LengSourc);
  end;
end;


WSocket_ioctlsocket - это аналог ioctlsocket. Но все равно ничего не работает.

Код на С++ у меня нет возможности проверить.

В принципе handle сокета я передаю, и нет разницы как он был создан через API или как компонент.

Автор: Dayana 4.2.2003, 23:53
Pegas, писала ответ с тобой одновременно.

Ты не мог бы дать основные ф-ции API, которые позволяют создать сокет и работать с ним?

Автор: Baa 5.2.2003, 01:30
Если я не ошибаюсь (давно это было), то в IFF_PROMISC mode может выставится токо RAW сокет.

Автор: <Spawn> 5.2.2003, 01:37
Цитата(Dayana @ 4.2.2003, 15:53)
Pegas, писала ответ с тобой одновременно.

Ты не мог бы дать основные ф-ции API, которые позволяют создать сокет и работать с ним?

Открой файл WinSock или IdWinSock2(Если Delphi 7). Тама есть эти самые функции.

Автор: <Spawn> 5.2.2003, 01:41
А так основные функции это -
Socket()
Bind()
CloseSocket()
Accept()
Send()
Recv()
SendTo()
RecvFrom()
Ну и их асинхронные аналоги(с приставкой WSA).
Причем перед их использованием необходимо загрузить WinSock
WSAStartUp()
и потом выгрузить
WSACleanUp;
Разумеется это не полный список функций, но для начала и их хватит)

Автор: Dayana 5.2.2003, 01:45
Делаю вот так

Цитата

var
  RcvPack : array [0..8024] of char;
  AddrSour : TSockAddr;
  i : integer;
  PackLen : integer;
  vWSAData : TWSAData;
  S : TSocket;
  SockAddr : TSockAddrIn;
  HostName : array[0..128] of char;
  pLocHost : PHostEnt;
  Flag : u_long;

begin
  FillChar(RcvPack, 8024, #0);
  GetHostName(HostName, 129);
  pLocHost := GetHostByName(HostName);
  WSAStartUp(MakeWord(2,2), vWSAData);
  S := Socket(AF_INET, SOCK_RAW, IPPROTO_IP);
  SockAddr.sin_family := AF_INET;
  SockAddr.sin_port := htons(5003);
  SockAddr.sin_addr.S_addr := PInAddr(pLocHost^.h_addr_list)^.S_addr;
  Bind(S, SockAddr, SizeOf(SockAddr));
  Flag := 1;
  ioctlsocket(S, SIO_RCVALL, Flag);
  for i := 1 to 10 do
    PackLen := recv(S, RcvPack, 8024, 0);
  CloseSocket(S);


открываю его как RAW.... но все равно ничего не получает...:-(

Автор: Dayana 5.2.2003, 01:46
<Spawn>, спасибо! Уже нашла...

Автор: Baa 5.2.2003, 01:50
Dayana попробуй порт выставить в 0...
з.ы. дома буду, че-нить придумаю...

Автор: Dayana 5.2.2003, 01:58
Baa, спасибочки!

Автор: Dayana 5.2.2003, 18:32
Baa, нашла в чем была ошибка. Совсем упустила из виду, что на компе установлены 2 сетевые карты. Одна с динамическим DNS для выхода в локальную сеть. А другая, с которой мне надо работать, с определенным IP и SUBNET MASK. Если отключаю локальную сеть и подключаю туда модем, т.е. в сетевую карту с динамическим DNS, то все работает. Но мне надо работать с другой сетевой картой.

Есть ли какая-нибудь возможность указать сокету с каким адаптером работать?

Автор: Baa 5.2.2003, 19:04
Дык при бинде ж указываешь ему на какой ип...
У тя gethostbyname возвращает первичный сетевой адрес, а вот вторичный остается не у дел... Пробуй сама заполнить структуру с адресом.

Автор: Dayana 5.2.2003, 19:31
Baa, все получилось! Спасибо! :-) Просто я думала, что не достаточно заполнять структруру с IP адресом, и надо еще что-то указывать типа MACа сетевой карты.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)