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

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

проблема с сообщениями в WinSock


syned ©   (2006-01-03 17:41:00) 

Добрый вечер!
Я пишу клиент-серверную прогу с помощью асинхронных сокетов.

объявляю константы
const
 WM_SOCKET_EVENT = WM_USER + 2; // константа сообщения
 MAXLEN = 8192; // размер буфера

Создаю сокет и перевожу в ассинхронный режим:

 aSock := socket(AF_INET,SOCK_DGRAM,0);
 // заполнение addr
 addr.sin_family := AF_INET;
 addr.sin_port := htons(55566);
 addr.sin_addr.S_addr := inet_addr('127.0.0.1');
 FillChar(addr.sin_zero,sizeof(addr.sin_zero),0);
 // привязываем слухающий сервер, и переводим в режим ожидания
 bind(aSock,addr,sizeOf(addr));
 listen(aSock,SOMAXCONN);
 // асинхронный селект, возникает событие WM_SOCKET_EVENT
 WSAAsyncSelect(aSock,Handle,WM_SOCKET_EVENT,FD_READ);
 Self.Caption := 'Сервер запущен!';

Отправляю широковещательное сообщение:

 ListBox1.Clear;
 s := socket(AF_INET,SOCK_DGRAM,0);
 // Отправляем опрос серваков
 saddr.sin_family := AF_INET;
 saddr.sin_port := htons(55566);
 saddr.sin_addr.S_addr := inet_addr('192.168.1.255');
 FillChar(addr.sin_zero,sizeof(addr.sin_zero),0);

 ps[0] := $FF;

 len := sizeOf(TSockAddr);
 t := SendTo(s,ps,1,0,saddr,len);
 if t <> 1 then
   begin
     ShowMessage('Ошибка посылки');
     Exit;
   end
 else
   ListBox1.Items.Add('Послан опрос! Список запущенных серверов');

для получения таких же программ в сети...

ну и самое главное, обработка сообщения...

procedure TForm1.WMSocketEvent(var msg : TMessage);
var
 sock : TSocket;
 sockError : integer;
 sockAddrr : TSockAddr;
 len, lenAddr : integer;
 ps : array [0..MAXLEN-1] of byte;
 res : integer;
 s, slocal, sremote : string;
 bufComp : Cardinal;
 p : PHostEnt;
 i, t : integer;
 str : string;
begin
 len := 8192;
 lenAddr := 16;
 bufComp := 256;
 sock := TSocket(msg.WParam);
 sockError := WSAGetSelectError(msg.LParam);
 if sockError <> 0 then
   begin
     ShowMessage('Ошибка!');
     closesocket(sock);
     Exit;
   end;
 if WSAGetSelectEvent(msg.LParam) = FD_READ then
   begin
     res := recvfrom(sock,ps,len,0,sockAddrr,lenAddr);
     if res = -1 then
       ListBox1.Items.Add('Ошибка получения данных')
     else
       begin
         // получаем локальный IP
         SetLength(s,bufComp);
         GetComputerName(PAnsiChar(s),bufComp);
         p := gethostbyname(PAnsiChar(s));
         slocal := inet_ntoa(PInAddr(p.h_addr_list^)^);
         sremote := inet_ntoa(sockAddrr.sin_addr);
         if slocal <> sremote then // если не с локального адреса
           begin
             case ps[0] of
               // пришли данные
               0 : begin
                     str := '';
                     for i := 1 to len-1 do
                       str := str + Chr(ps[i]);
                     ListBox2.Items.Add('Получены данные от '+inet_ntoa(SockAddrr.sin_addr)+': '+str);
                   end;
               // пришел опрос
               $FF : begin
                       ps[0] := $FE;
                       t := SendTo(sock,ps,1,0,sockAddrr,lenAddr);
                       if t <> 1 then
                         ListBox2.Items.Add('Ошибка послания IP')
                       else
                         ListBox2.Items.Add('IP успешно послан');
                     end;
                // Пришло подтверждение о доставке
               $FA : ListBox2.Items.Add('Данные для ' + inet_ntoa(SockAddrr.sin_addr) + ' успешно доставлены');
               // Пришел IP
               $FE : ListBox1.Items.Add(inet_ntoa(SockAddrr.sin_addr));
             end;
           end;
       end;
   end;
end;

и у меня возникает проблемма, отсылаю широковещательную посылку, данные приходят, IP посылается и все второй раз сообщение FD_READ никогда не приходит.

Должно работать так программа отсылает широковещательную посылку а другие в ответ на этот запрос высылают ответ и в листбокс заносятся все IP программ запущенных в сети...

Подскажите где ошибка, а то я не могу разобратся...


FrykT   (2006-01-03 19:09:00) [1]

closeSocket(Sock) забыл.


FrykT   (2006-01-03 19:07:00) [2]

И сделай  процедуру отправки нормальную:

function UdpSend(AHost: string; APort: Integer; AStr: string): boolean;
var
 buf: array[0..7990] of char;
 Sock: TSocket;
 addr: TSockAddr;
 SockOPT: BOOL;
begin
 Result := false;
 Sock := Socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 if Sock = INVALID_SOCKET then
   exit;
 addr.sin_family := AF_INET;
 addr.sin_port := htons(APort);
 addr.sin_addr.S_addr := Inet_Addr(Pchar(AHost));
 FillChar(addr.sin_zero,sizeof(addr.sin_zero),0);
 SockOPT := true;
 SetSockOpt(sock,SOL_SOCKET,SO_BROADCAST,PChar(@SockOpt),SizeOf(SockOpt));
 FillChar(buf, sizeof(buf), #0);
 Buf := AStr;
 SendTo(Sock, buf, sizeof(buf), 0, addr, sizeof(addr));
 Result := true;
end;


FrykT   (2006-01-03 19:00:00) [3]

Вот ПРИКОЛ твой :
addr.sin_addr.S_addr := inet_addr('127.0.0.1');

надо вот так:
addr.sin_addr.S_addr := htonl(INADDR_ANY);


syned   (2006-01-03 18:59:00) [4]

ладно, всем спасибо, я домой... буду мучатся завтра...


syned   (2006-01-03 18:57:00) [5]

я рехнусь с этими сокетами... :(


syned   (2006-01-03 18:56:00) [6]

t = 1, данные посылаются...


FrykT   (2006-01-03 18:53:00) [7]

Посмотри что в t приходит в отладчике. Если  -1, то  это SOCKET_ERROR


syned   (2006-01-03 18:41:00) [8]

Но всеравно решение не пришло еще раз повторяю, широковещательная рассылка приходит, но после этого куска кода сообщение FD_READ должно произойти еще раз так как посылаются данные:
              $FF : begin
                      ps[0] := $FE;
                      t := SendTo(sock,ps,1,0,sockAddrr,lenAddr);
                      if t <> 1 then
                        ListBox2.Items.Add('Ошибка послания IP')
                      else
                        ListBox2.Items.Add('IP успешно послан');
                    end;


syned   (2006-01-03 18:34:00) [9]

для разрешения широковещательной посылки


syned   (2006-01-03 18:34:00) [10]

А еще подскажите какое значение должен иметь параметр SockOpt
для функции
SetSockOpt(sock,SOL_SOCKET,SO_BROADCAST,PChar(@SockOpt),SizeOf(SockOpt));


syned   (2006-01-03 18:26:00) [11]

ок, спасибо


Piter   (2006-01-03 18:24:00) [12]

syned ©   (03.01.06 18:22) [4]
Так я и посылаю по UDP


ага, посылаешь ты по UDP, только вот Windows об этом ничего не знает. А так все путем.


Piter   (2006-01-03 18:23:00) [13]

а перед этим еще неплохо было бы выставить работу по протоколу UDP:

... := Socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);


syned   (2006-01-03 18:22:00) [14]

Piter ©   (03.01.06 18:07) [1]

syned ©   (03.01.06 17:41)
и у меня возникает проблемма, отсылаю широковещательную посылку

я вот всегда думал, что широковещательные запросы должны по протоколу UDP посылаться.

Так я и посылаю по UDP

To FrykT
я смотрел в дебаггере, широковещательная приходит, и больше сообщение FD_READ не возникает


FrykT   (2006-01-03 18:14:00) [15]

да, кстати. Перед отправкой сообщения вот это надо.
SetSockOpt(sock,SOL_SOCKET,SO_BROADCAST,PChar(@SockOpt),SizeOf(SockOpt));


FrykT   (2006-01-03 18:11:00) [16]

А что это за хреновина в procedure WMSocketEvent напихана? Поставь брекпоинт в WMSocketEvent после BEGIN и смотри, возникает ли событие, далее по обстоятельствам


Piter   (2006-01-03 18:07:00) [17]

syned ©   (03.01.06 17:41)
и у меня возникает проблемма, отсылаю широковещательную посылку


я вот всегда думал, что широковещательные запросы должны по протоколу UDP посылаться.


Наверх

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