Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Client/ServerSockets. Как найти все сокеты, активные в сети? [D6, Win2k]


Страницы:   1 2

Курдль ©   (2005-07-28 11:43:00) 

Привет, коллеги!

Нужно простое решение для поиска серверов внутри локальной сети. Допустим, что у них открыты сокеты на прослушивание по одному и тому же порту.

На низшем уровне, вроде, все понятно как делалось. Ставились прослушиватели на определенный порт, а с клиента отправлялся широковещательный запрос. Оставалось поймать и расшифровать
все ответы. А как это сделать средствами Delphi?

Наверняка уже обсуждалось, так что можете просто отправить на нужную ветку.


Eraser   (2005-09-12 13:43:00) [1]

Курдль ©   (11.09.05 22:42) [25]
Делфям такое и не снилось :(


А как же D8/2005 ? )

UDPClient, TCPListener и мн.др. да все с асинхронными методами!

Сомнительное приемущество.


Fay   (2005-09-12 00:14:00) [2]

2 Курдль ©   (11.09.05 22:42) [25]
> особенно Digitman ©, который заставил меня разобраться
> в существе вопроса
Преподобный Digitman обычно именно этого и добивается. IMHO, это лучшая подмога.

>> Делфям такое и не снилось :(
У них ("Делфей") хватает наяву.
Это как "Биться, так биться. Но зачем в #опу кричать?"...


Курдль   (2005-09-11 22:42:00) [3]

Спасибо всем за дельные советы, особенно Digitman ©, который заставил меня разобраться в существе вопроса, хоть на это ушло больше времени, чем планировалось. Правда по ходу "дознания" удалось выяснить неоспоримые преимущества "вижуал кролика" перед делфями и полностью переписать прогу на нем. Многообразие предопределенных классов-наследников Socket поразило мое воспаленное воображение. UDPClient, TCPListener и мн.др. да все с асинхронными методами! Прэлестно! А уж что говорить про ".NET Remoting"... Делфям такое и не снилось :(


Digitman   (2005-07-28 15:30:00) [4]


> скажу лишь что мне так привычней


.. особенно в случаях, когда собеседник (оппонент) не зарегистрирован в Форуме как постоянный участник


Digitman   (2005-07-28 15:28:00) [5]


> Курдль   (28.07.05 13:53) [15]
> Надеюсь, что с этого момента мы будем общаться только "на
> Вы".


без вопросов.

на "Вы" - значит на "Вы"... за фамильярность-панибратство готов принести персональные извинения, коль они того стоят в дан.ситуации

скажу лишь что мне так привычней.


> На этот форум приходят за помощью


Да.


> Именно в надежде, что ее "Дадут", а не "Продадут" или боросят,
> как кость


Да. Помощь не м.б. ассоциирована с "продать".

"Бросить как кость" - совершенно неуместно в дан.случае, ибо вопрос, повторяю, был задан КРАЙНЕ туманно и некорректно. И что было "брошенной костью" в дан.случае - весьма и весьма неоднозначтно.... "Кость" за "кость" ..


> с работой в сетях у меня как-то не задалось


я тоже с этого начинал - ничего страшного.

когда-то меня на этом форуме тоже ткнули носом  - и я пошел читать док-цию и решил ту (ти все последующие) задачи самостоятельно.


> за дельный совет, содержащийся .. в последней
> строчке


преодоление некомпетентности д.б. быть начато не с "дай", а с поиска в Сети инф-ции на тему "сетевые протоколы информационного обмена"


Alexey_FireMan   (2005-07-28 14:57:00) [6]

Что конкретно ты собираешся передавать и проверять?
Если ты хочешь проверить включены ли машины у тебя в локалке то проще всего использовать UDP. На (Клиентских машинах) просто создаеш сокет скажем порт $3218, а с (серверной) отсылаеш широковещательный запрос, в свою же очередь клиент получив запрос и адрес (серверной) выполняет (подлючается по TCP или отсылает пакет с подтверждением о включенности по UDP) действия.
Такой способ не сильно грузит сетку, т.е. сервер не отослал запрос клиент сидит тихо!


Курдль   (2005-07-28 14:49:00) [7]

Ага, спасибо. Что-то делфя сама не нашла unit Winsock2.
Сейчас попробую вручную.


Polevi   (2005-07-28 14:42:00) [8]

setsockopt (ASocket,SOL_SOCKET,SO_BROADCAST,PChar(@BroadCast),sizeof(boolean));

убери, он тебе не нужен


Polevi   (2005-07-28 14:37:00) [9]

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Winsock2,
 StdCtrls, Scktcomp, ExtCtrls;

const
 UDPPort=222;

type
 TT=class(TThread)
 private
   FSocket:TSocket;
   FAddr: TSockAddrIn;
   FWnd:THandle;
 protected
   procedure Execute;override;
 public
   constructor Create(AWnd:THandle);reintroduce;
 end;

type
 TForm1 = class(TForm)
   Timer1: TTimer;
   Memo1: TMemo;
   Button1: TButton;
   procedure FormCreate(Sender: TObject);
   procedure Button1Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
   procedure OnMsg(var Msg:TMessage);message WM_USER+1;
 end;

var
 Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
var
 WSAData:TWSAData;
begin
 if WSAStartup($0202,WSAData)<>0 then
   raise Exception.Create('Cannot load winsock!');
 TT.Create(Handle);
end;

procedure TForm1.OnMsg(var Msg: TMessage);
begin
 Memo1.Lines.Add(PChar(Msg.wParam));
end;

constructor TT.Create(AWnd: THandle);
begin
 FWnd:=AWnd;
 inherited Create(false);
end;

procedure TT.Execute;
var
 Buffer:Pointer;
 Len:integer;
 evt:THandle;
 bytesRecvd:integer;
const
 bufLen=512;
begin
 GetMem(Buffer,bufLen);
 try
   try
     FSocket := socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
     FAddr.sin_family := AF_INET;
     FAddr.sin_addr.s_addr := INADDR_ANY;
     FAddr.sin_port := htons(UDPPort);
     if bind(FSocket, @FAddr, SizeOf(FAddr))=SOCKET_ERROR then
       RaiseLastWin32Error;
     evt:=CreateEvent(nil,false,false,nil);
     WSAEventSelect(FSocket,evt,FD_READ);
     while not Terminated do
     begin
       WSAWaitForMultipleEvents(1,@evt,false,INFINITE,false);
       Len:=sizeof(FAddr);
       bytesRecvd:=recvfrom(FSocket,Buffer^,bufLen,0,FAddr,Len);
       if bytesRecvd=SOCKET_ERROR then
         RaiseLastWin32Error;
       SendMessage(FWnd,WM_USER+1,Integer(Buffer),bytesRecvd);
     end;
     CloseHandle(evt);
     closesocket(FSocket);
   except
   end;
 finally
   FreeMem(Buffer);
 end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 ASocket:TSocket;
 Addr: TSockAddrIn;
 Len:integer;
 BroadCast:boolean;
begin
 BroadCast:=false;
 ASocket := socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 setsockopt (ASocket,SOL_SOCKET,SO_BROADCAST,PChar(@BroadCast),sizeof(boolean));
 Addr.sin_family := AF_INET;
 Addr.sin_addr.s_addr := inet_addr(PChar('192.168.1.22'));
 Addr.sin_port := htons(UDPPort);
 Len:=sizeof(Addr);
 if sendto(ASocket,PChar('hello world')^,12,0,Addr,Len)=SOCKET_ERROR then
   RaiseLastWin32Error;
 closesocket(ASocket);
end;

end.


Курдль   (2005-07-28 14:28:00) [10]

//ты прав, но не факт что у него UDP сервер

У меня пока нет никакого сервера.
И я не ограничен никакими строгими условиями сохранности / безопасности данных. Если вы, как высококвалифицированные специалисты, посоветуете мне UDP - я сработаю и с ним.
Если у кого-то есть кусочек кода, который мог бы стать "ответной частью" процедуры, любезно предоставленной kblc ©, я был бы просто счастлив!


Polevi   (2005-07-28 14:20:00) [11]

>kblc ©   (28.07.05 13:59) [16]
ты прав, но не факт что у него UDP сервер


kblc   (2005-07-28 13:59:00) [12]

2Polevi:
 send используеться для TCP клиента.

2All: нужно использовать sendto, а на сервере нужно использовать recvfrom


Курдль   (2005-07-28 13:53:00) [13]

Уважаемый Digitman ©!
Надеюсь, что с этого момента мы будем общаться только "на Вы".

На этот форум приходят за помощью. Именно в надежде, что ее "Дадут", а не "Продадут" или боросят, как кость.
В былые времена я охотно делился своими знаниями, касающимися работы с данными. А вот с работой в сетях у меня как-то не задалось.

Спасибо за подробные выкладки моей некомпетентности.
А особенно - за дельный совет, содержащийся (к сожаленнию только) в последней строчке.


Digitman   (2005-07-28 13:39:00) [14]


> Курдль   (28.07.05 13:09) [12]


"мля"кай с пацанами в подворотне.

а здесь будь любезен сформулировать вопрос как положено - кратко, внятно, точно ..


> Ставились прослушиватели на определенный порт


вот как тебя понять ? ЧТО за "прослушиватели" такие ?

UDP-сервер как таковой не существует - любоеUDP-гнездо способно выполнять ф-ции некоего рода "клиента" или "сервера", в отличии от TCP-гнезда ..

UDP-гнездо ничего не "прослушивает" - оно просто принимает дейтаграммы с любого адреса в сети, интерфейс которой был указан при его bind(), в т.ч. и дейтаграммы, разосланные бродкастом любым другим (передающим) UDP-гнездом

Listen() же ("прослушивание вх.запросов на соединение") вообще не применим к UDP-гнездам, потому как этот механизм используется лишь для протоколов, подразумевающих установку логического p2p-соединения перед тем как будет начат собстенно прикладной инф.обмен между двумя гнездами

Так что твое "прослушивание" как способность ожидать и принимать UDP-гнездом адресованые ему (непосредственно или бродкастом) дейтаграммы и "прослушивание" как способность ожидать TCP-гнездом входящие клиентские запросы на соединение и акцептировать их (возможно - условно) - это две разные разницы !


> дай пример


что за "дай" ?! ты в богадельню явился ?
и что значит "пример" ? ты даже не сподобился уточнить, гнезда как WinsockAPI-объекты или гнезда как Делфи-объекты тебя интересует, а пример при этом (непонятно для каких гнезд) тебе вынь да положь ?


> как ответить


на WinsockAPI так и ответь - sendto() ..

в recvfrom() предпосл.параметром ты получаешь адрес отправителя принятой дейтаграммы, его же и используй в кач-ве адреса получателя ответной дейтаграммы


Polevi   (2005-07-28 13:18:00) [15]

используй ф-ию send


Курдль   (2005-07-28 13:09:00) [16]

> Digitman ©

Мля! Какая ж ты зануда!!!
Мне было бы достаточно получить по UDP сетевые адреса активных в данный момент элементов распределенной системы. Как оно все у меня будет работать тебе надо?

Лучше последуй примеру доброго и щедрого, хоть и ироничного kblc ©
и дай пример, как ответить на broadcast сообщение!


Digitman   (2005-07-28 12:54:00) [17]


> Вы же мой вопрос в конце концов поняли?


я ? нет) .. я так и не понял, кто и что там у тебя "слушает" на серв.стороне - ты ведь "навскидочку" упомянул Listen(), всуе тэкскэть ..

у TCP-сервера д.б. TCP-клиент

а TCP-клиент не умеет делать broadcast, его умеет делать UDP-"клиент"

и каким макаром ты умудряешься "снюхать" UDP-"клиента" с TCP-сервером - просто ума не приложу)


Курдль   (2005-07-28 12:52:00) [18]

Спасибо, kblc ©!

Все отработало, как надо.
Ща только почищу все, что касается MS SQL и вперед!


Курдль   (2005-07-28 12:45:00) [19]

Спасибо. Пошел разбираться.
Извиняюсь за крайнее косноязычие, но Вы же мой вопрос в конце концов поняли?! :)


kblc   (2005-07-28 12:39:00) [20]

procedure Tfm_SQL_Update.GetServersList(Storage: TStrings);
var
 hSocket: TSOCKET;
 WSAData: TWSAData;
 Buf: array[0..65535] of byte;
 i,iBeg,tRes,tLenSA,tLenBufRecv,tFlagStep: integer;
 tLenBufIOCTL: u_long;
 S,S2,S3: AnsiString;
 saSQLSend,saSQLRecv: sockaddr_in;
 Data: byte;
const
 fBroadcast: boolean = TRUE;
begin
 Data:=$02;
 Storage.Clear;
 WSAStartup(MakeWord(2,2), WSAData);

 hSocket:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
 if (hSocket = INVALID_SOCKET) then exit;

 tRes:=setsockopt(hSocket,SOL_SOCKET,SO_BROADCAST,@fBroadcast,sizeof(BOOL));
 if (tRes = SOCKET_ERROR) then
 begin
   closesocket(hSocket);
   exit;
 end;

 saSQLSend.sin_family :=AF_INET;
 saSQLSend.sin_port:=htons(1434);
 saSQLSend.sin_addr.s_addr:=htonl(INADDR_BROADCAST);
 tRes:=sendto(hSocket,Data,1,0,saSQLSend,sizeof(SOCKADDR_IN));
 if (tRes=SOCKET_ERROR) then
 begin
   closesocket(hSocket);
   exit;
 end;
 Sleep(100);
 tRes:=ioctlsocket(hSocket,FIONREAD,tLenBufIOCTL);
 if (tRes=SOCKET_ERROR) then
 begin
   closesocket(hSocket);
   exit;
 end;
 
 if (tLenBufIOCTL>0) then
 begin
   tFlagStep:=0;
   tLenSA:=sizeof(SOCKADDR_IN);
   saSQLRecv:=saSQLSend;
   while tLenBufIOCTL>0 do
   begin
     tLenBufRecv:=recvfrom(hSocket,Buf,65535,0,saSQLRecv,tLenSA);
     tLenBufIOCTL:=tLenBufIOCTL-tLenBufRecv;
     if(tLenBufRecv=SOCKET_ERROR) then
     begin
       closesocket(hSocket);
       exit;
     end;
     iBeg:=1;
     S2:='';
     for i:=3 to tLenBufRecv-3 do S2:=S2+Chr(Buf[i]);
     tLenBufRecv:=tLenBufRecv-3;
     for i:=1 to tLenBufRecv-3 do
     begin
       if(S2[i]=';') then
       begin
         S:=Copy(S2,iBeg,i-iBeg);
         if (tFlagStep=1) then S3:=S;
         if (tFlagStep=2) then
         begin
           if(S<>'MSSQLSERVER') then S3:=S3+('\\'+S);
           Storage.Add(S3);
           S3:='';
         end;
         tFlagStep:=0;
         if(S='ServerName') then tFlagStep:=1;
         if(S='InstanceName') then tFlagStep:=2;
         iBeg:=i+1;
       end;
     end;
   end;
 end;
 closesocket(hSocket);
 WSACleanup;
 Storage.Add('LOCALHOST');
end;


Вот тебе пример поиска SQL сервером, которые открывают 1434 UDP порт.
Разберёшься?


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо