![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
проблема с сообщениями в 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 посылаться.